Countdown timer
Product details display
import React, { useState, useEffect } from 'react';
import { Flexbox, Text } from '@evlop/native-components';
function Digit({ char, textStyle }) {
const fontSize = (textStyle && textStyle.fontSize) || 18;
return (
<Text color={textStyle.color} fontSize={fontSize} fontWeight={textStyle.fontWeight} style={{ lineHeight: fontSize * 1.25, textAlign: 'center' }}>
{char}
</Text>
);
}
function StaticNumber({ value, textStyle = {} }) {
const str = String(value);
return (
<Flexbox flexDirection="row" alignItems="center">
{str.split('').map((ch, idx) => (
<Digit key={idx} char={ch} textStyle={textStyle} />
))}
</Flexbox>
);
}
// The component now accepts a `data` prop (provided by the builder). Make the countdown configurable
const Countdown:AppBlock =function ({ data = {} }) {
const [timeLeft, setTimeLeft] = useState({});
const targetDateString = data.targetDate || '2026-01-01T00:00:00';
const target = new Date(targetDateString);
const calculateTimeLeft = () => {
const now = new Date();
const difference = +target - +now;
if (difference <= 0) return { days: 0, hours: 0, minutes: 0, seconds: 0 };
return {
days: Math.floor(difference / (1000 * 60 * 60 * 24)),
hours: Math.floor((difference / (1000 * 60 * 60)) % 24),
minutes: Math.floor((difference / 1000 / 60) % 60),
seconds: Math.floor((difference / 1000) % 60),
};
};
useEffect(() => {
setTimeLeft(calculateTimeLeft());
const id = setInterval(() => setTimeLeft(calculateTimeLeft()), 1000);
return () => clearInterval(id);
// target may change via data prop — update when it does
}, [targetDateString]);
const formatNumber = (n) => String(n).padStart(2, '0');
const intervals = [
{ key: 'days', label: 'DAYS' },
{ key: 'hours', label: 'HOURS' },
{ key: 'minutes', label: 'MIN' },
{ key: 'seconds', label: 'SEC' },
];
// colorful palette for timer blocks (kept default but could be exposed later)
const timerColors = ['#FFEDD5', '#EDE9FE', '#DBEAFE', '#ECFCCB'];
const timerTextColors = ['#9A3412', '#5B21B6', '#1E40AF', '#365314'];
const showLabels = data.showLabels !== undefined ? Boolean(data.showLabels) : true;
const timerComponents = intervals.map((it, idx) => (
<Flexbox
key={it.key}
bg={timerColors[idx % timerColors.length]}
p="xs"
borderRadius={10}
alignItems="center"
justifyContent="center"
flexDirection="column"
style={{ minWidth: 56, marginHorizontal: 6, shadowColor: '#000', shadowOpacity: 0.03, shadowRadius: 6 }}
>
<StaticNumber value={formatNumber(timeLeft[it.key] ?? 0)} textStyle={{ color: timerTextColors[idx % timerTextColors.length], fontSize: 16, fontWeight: '800' }} />
{showLabels && <Text color="#475569" fontSize="xs">{it.label}</Text>}
</Flexbox>
));
const title = data.title || 'Countdown to 2026';
const subtitle = data.subtitle || 'A colorful countdown.';
return (
<Flexbox
bg="#fff7ed"
p="xl"
gap={20}
flexDirection="column"
alignItems="center"
justifyContent="center"
style={{ flex: 1 }}
>
<Flexbox
bg="white"
borderRadius={16}
p="lg"
gap={12}
flexDirection="column"
alignItems="center"
style={{ width: '100%', maxWidth: 720, elevation: 3 }}
>
{/* colorful stripe */}
<Flexbox flexDirection="row" style={{ width: '100%', height: 8, borderRadius: 8, overflow: 'hidden' }}>
<Flexbox bg="#FB7185" style={{ flex: 1 }} />
<Flexbox bg="#F59E0B" style={{ flex: 1 }} />
<Flexbox bg="#10B981" style={{ flex: 1 }} />
<Flexbox bg="#7C3AED" style={{ flex: 1 }} />
</Flexbox>
<Text color="#6D28D9" fontSize="2xl" fontWeight="bold">{title}</Text>
<Text color="#374151" fontSize="sm">{subtitle}</Text>
<Flexbox flexDirection="row" alignItems="center" justifyContent="center" style={{ width: '100%', flexWrap: 'nowrap' }}>
{timerComponents}
</Flexbox>
</Flexbox>
</Flexbox>
);
}
export default Countdown;
{
"title": "Countdown to 2026",
"subtitle": "A colorful, animated countdown — numbers slide in from the bottom as they update.",
"targetDate": "2026-01-01T00:00:00",
"showLabels": true
}Loading...