feat: Add configurable draw cycles, improve UX
Backend: - Add configurable draw cycle settings (minutes/hourly/daily/weekly/custom) - Add CYCLE_TYPE, CYCLE_INTERVAL_*, CYCLE_DAILY_TIME, CYCLE_WEEKLY_* env vars - Add SALES_CLOSE_BEFORE_DRAW_MINUTES and CYCLES_TO_GENERATE_AHEAD - Fix SQLite parameter issue in scheduler Frontend: - Add 'Save This Link' section with copy button on ticket status page - Improve draw animation to show immediately when draw starts - Show 'Waiting for next round...' instead of 'Drawing Now!' after draw - Hide Buy Tickets button when waiting for next round - Skip draw animation if no tickets were sold - Keep winner screen open longer (15s) for next cycle to load - Auto-refresh to next lottery cycle after draw Telegram Bot: - Various improvements and fixes
This commit is contained in:
@@ -18,6 +18,21 @@ export default function TicketStatusPage() {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [data, setData] = useState<any>(null);
|
||||
const [autoRefresh, setAutoRefresh] = useState(true);
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const ticketUrl = typeof window !== 'undefined'
|
||||
? `${window.location.origin}/tickets/${ticketId}`
|
||||
: '';
|
||||
|
||||
const copyLink = async () => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(ticketUrl);
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
} catch (err) {
|
||||
console.error('Failed to copy:', err);
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
loadTicketStatus();
|
||||
@@ -86,6 +101,48 @@ export default function TicketStatusPage() {
|
||||
{STRINGS.ticket.title}
|
||||
</h1>
|
||||
|
||||
{/* Save This Link */}
|
||||
<div className="bg-gradient-to-r from-blue-900/30 to-purple-900/30 border border-blue-700/50 rounded-xl p-6 mb-6">
|
||||
<div className="flex items-start gap-4">
|
||||
<div className="text-3xl">🔖</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="text-lg font-semibold text-white mb-2">Save This Link!</h3>
|
||||
<p className="text-gray-300 text-sm mb-3">
|
||||
Bookmark or save this page to check if you've won after the draw. This is your only way to view your ticket status.
|
||||
</p>
|
||||
<div className="flex flex-col sm:flex-row gap-2">
|
||||
<div className="flex-1 bg-gray-800/80 rounded-lg px-3 py-2 font-mono text-sm text-gray-300 break-all">
|
||||
{ticketUrl || `/tickets/${ticketId}`}
|
||||
</div>
|
||||
<button
|
||||
onClick={copyLink}
|
||||
className={`px-4 py-2 rounded-lg font-medium transition-all flex items-center justify-center gap-2 ${
|
||||
copied
|
||||
? 'bg-green-600 text-white'
|
||||
: 'bg-blue-600 hover:bg-blue-500 text-white'
|
||||
}`}
|
||||
>
|
||||
{copied ? (
|
||||
<>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M5 13l4 4L19 7" />
|
||||
</svg>
|
||||
Copied!
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3" />
|
||||
</svg>
|
||||
Copy Link
|
||||
</>
|
||||
)}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Purchase Info */}
|
||||
<div className="bg-gray-900 rounded-xl p-6 mb-6 border border-gray-800">
|
||||
<div className="grid grid-cols-2 gap-4 text-sm">
|
||||
|
||||
Reference in New Issue
Block a user