react-native-countdown-eggmun
Version:
A customizable countdown component for React Native
213 lines (212 loc) • 9.88 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
var react_1 = __importStar(require("react"));
var react_native_1 = require("react-native");
var DEFAULT_DIGIT_STYLE = { backgroundColor: '#00f7ff' };
var DEFAULT_DIGIT_TXT_STYLE = { color: '#000' };
var DEFAULT_TIME_LABEL_STYLE = { color: '#000' };
var DEFAULT_SEPARATOR_STYLE = { color: '#000' };
var DEFAULT_TIME_TO_SHOW = ['D', 'H', 'M', 'S'];
var DEFAULT_TIME_LABELS = {
d: 'D',
h: 'H',
m: 'M',
s: 'S',
};
var formatTime = function (days, hours, minutes, seconds) {
return "".concat(String(days).padStart(2, '0'), ":").concat(String(hours).padStart(2, '0'), ":").concat(String(minutes).padStart(2, '0'), ":").concat(String(seconds).padStart(2, '0'));
};
var CountDown = function (_a) {
var _b = _a.digitStyle, digitStyle = _b === void 0 ? DEFAULT_DIGIT_STYLE : _b, _c = _a.digitTxtStyle, digitTxtStyle = _c === void 0 ? DEFAULT_DIGIT_TXT_STYLE : _c, _d = _a.timeLabelStyle, timeLabelStyle = _d === void 0 ? DEFAULT_TIME_LABEL_STYLE : _d, _e = _a.separatorStyle, separatorStyle = _e === void 0 ? DEFAULT_SEPARATOR_STYLE : _e, _f = _a.timeToShow, timeToShow = _f === void 0 ? DEFAULT_TIME_TO_SHOW : _f, _g = _a.showSeparator, showSeparator = _g === void 0 ? false : _g, _h = _a.showLabels, showLabels = _h === void 0 ? false : _h, _j = _a.size, size = _j === void 0 ? 15 : _j, until = _a.until, onChange = _a.onChange, onPress = _a.onPress, onFinish = _a.onFinish, _k = _a.running, running = _k === void 0 ? true : _k, _l = _a.autoRestart, autoRestart = _l === void 0 ? false : _l, style = _a.style, _m = _a.timeLabels, timeLabels = _m === void 0 ? DEFAULT_TIME_LABELS : _m;
var _o = (0, react_1.useState)(Math.max(until, 0)), remainingTime = _o[0], setRemainingTime = _o[1];
var _p = (0, react_1.useState)(null), wentBackgroundAt = _p[0], setWentBackgroundAt = _p[1];
var timerRef = (0, react_1.useRef)(null);
var isMountedRef = (0, react_1.useRef)(true);
var lastUpdateTimeRef = (0, react_1.useRef)(Date.now());
(0, react_1.useEffect)(function () {
isMountedRef.current = true;
return function () {
isMountedRef.current = false;
};
}, []);
(0, react_1.useEffect)(function () {
if (isMountedRef.current) {
setRemainingTime(Math.max(until, 0));
}
}, [until]);
var handleAppStateChange = (0, react_1.useCallback)(function (nextAppState) {
if (!isMountedRef.current)
return;
if (nextAppState === 'active' && wentBackgroundAt && running) {
var diff = Math.floor((Date.now() - wentBackgroundAt) / 1000.0);
var newTime = Math.max(0, remainingTime - diff);
// 시, 분, 초 계산
var hours = Math.floor(newTime / 3600);
var minutes = Math.floor((newTime % 3600) / 60);
var seconds = newTime % 60;
// 올바른 형식으로 시간 설정
setRemainingTime(hours * 3600 + minutes * 60 + seconds);
}
if (nextAppState === 'background') {
setWentBackgroundAt(Date.now());
}
}, [remainingTime, running, wentBackgroundAt]);
(0, react_1.useEffect)(function () {
var subscription = react_native_1.AppState.addEventListener('change', handleAppStateChange);
return function () {
subscription.remove();
};
}, [handleAppStateChange]);
(0, react_1.useEffect)(function () {
if (remainingTime === 0 && running) {
onFinish === null || onFinish === void 0 ? void 0 : onFinish();
}
}, [remainingTime, running]);
var handleTimerTick = (0, react_1.useCallback)(function () {
if (!isMountedRef.current)
return;
var now = Date.now();
var timeSinceLastUpdate = now - lastUpdateTimeRef.current;
if (timeSinceLastUpdate >= 1000) {
setRemainingTime(function (prevTime) {
if (prevTime <= 0) {
if (autoRestart) {
return until;
}
if (timerRef.current) {
clearInterval(timerRef.current);
timerRef.current = null;
}
return 0;
}
var newTime = prevTime - 1;
onChange === null || onChange === void 0 ? void 0 : onChange(newTime);
lastUpdateTimeRef.current = now;
return newTime;
});
}
}, [autoRestart, until]);
(0, react_1.useEffect)(function () {
if (!running) {
if (timerRef.current) {
clearInterval(timerRef.current);
timerRef.current = null;
}
return;
}
timerRef.current = setInterval(handleTimerTick, 1000);
return function () {
if (timerRef.current) {
clearInterval(timerRef.current);
timerRef.current = null;
}
};
}, [running, handleTimerTick]);
var getTimeLeft = (0, react_1.useCallback)(function () {
return {
seconds: remainingTime % 60,
minutes: Math.floor(remainingTime / 60) % 60,
hours: Math.floor(remainingTime / (60 * 60)) % 24,
days: Math.floor(remainingTime / (60 * 60 * 24)),
};
}, [remainingTime]);
var renderDigit = function (digit) { return (<react_native_1.View style={[styles.digitCont, { width: size * 2.3, height: size * 2.6 }, digitStyle]}>
<react_native_1.Text style={[styles.digitTxt, { fontSize: size }, digitTxtStyle]}>{digit}</react_native_1.Text>
</react_native_1.View>); };
var renderLabel = function (label) {
if (!label || !showLabels)
return null;
return <react_native_1.Text style={[styles.timeTxt, { fontSize: size / 1.8 }, timeLabelStyle]}>{label}</react_native_1.Text>;
};
var renderDoubleDigits = function (label, digits) { return (<react_native_1.View style={styles.doubleDigitCont}>
<react_native_1.View style={styles.timeInnerCont}>{renderDigit(digits)}</react_native_1.View>
{renderLabel(label)}
</react_native_1.View>); };
var renderSeparator = function () { return (<react_native_1.View style={{ justifyContent: 'center', alignItems: 'center' }}>
<react_native_1.Text style={[styles.separatorTxt, { fontSize: size * 1.2 }, separatorStyle]}>:</react_native_1.Text>
</react_native_1.View>); };
var renderCountDown = function () {
var _a = getTimeLeft(), days = _a.days, hours = _a.hours, minutes = _a.minutes, seconds = _a.seconds;
var newTime = formatTime(days, hours, minutes, seconds).split(':');
var Component = onPress ? react_native_1.TouchableOpacity : react_native_1.View;
return (<Component style={styles.timeCont} onPress={onPress}>
{timeToShow.includes('D') && renderDoubleDigits(timeLabels.d, newTime[0])}
{showSeparator && timeToShow.includes('D') && timeToShow.includes('H') && renderSeparator()}
{timeToShow.includes('H') && renderDoubleDigits(timeLabels.h, newTime[1])}
{showSeparator && timeToShow.includes('H') && timeToShow.includes('M') && renderSeparator()}
{timeToShow.includes('M') && renderDoubleDigits(timeLabels.m, newTime[2])}
{showSeparator && timeToShow.includes('M') && timeToShow.includes('S') && renderSeparator()}
{timeToShow.includes('S') && renderDoubleDigits(timeLabels.s, newTime[3])}
</Component>);
};
return <react_native_1.View style={style}>{renderCountDown()}</react_native_1.View>;
};
var styles = react_native_1.StyleSheet.create({
timeCont: {
flexDirection: 'row',
justifyContent: 'center',
},
timeTxt: {
color: 'white',
marginVertical: 2,
backgroundColor: 'transparent',
},
timeInnerCont: {
flexDirection: 'row',
justifyContent: 'center',
alignItems: 'center',
},
digitCont: {
borderRadius: 10,
marginHorizontal: 2,
alignItems: 'center',
justifyContent: 'center',
},
doubleDigitCont: {
justifyContent: 'center',
alignItems: 'center',
},
digitTxt: {
color: 'white',
fontWeight: 'bold',
fontVariant: ['tabular-nums'],
},
separatorTxt: {
backgroundColor: 'transparent',
fontWeight: 'bold',
},
});
exports.default = CountDown;
;