diff --git a/src/app/[lang]/(blank-layout-pages)/draw/page.tsx b/src/app/[lang]/(blank-layout-pages)/draw/page.tsx index 1217f13..c357efb 100644 --- a/src/app/[lang]/(blank-layout-pages)/draw/page.tsx +++ b/src/app/[lang]/(blank-layout-pages)/draw/page.tsx @@ -26,16 +26,24 @@ interface WinnerHistory { const RandomDrawApp: React.FC = () => { const [spinRows, setSpinRows] = useState([]); - const [numberOfRows, setNumberOfRows] = useState(4); + const [numberOfRows, setNumberOfRows] = useState(5); const [winnersHistory, setWinnersHistory] = useState([]); const [isRevealingWinners, setIsRevealingWinners] = useState(false); const [revealedWinners, setRevealedWinners] = useState>(new Set()); + const [isSequentialSpinning, setIsSequentialSpinning] = useState(false); + const [currentSpinningRow, setCurrentSpinningRow] = useState(null); + const [selectedPrize, setSelectedPrize] = useState(1); // 1 for Emas 0.25 Gram, 2 for Emas 3 Gram const audioContextRef = useRef(null); const tickIntervalRefs = useRef>(new Map()); const shuffleIntervalRefs = useRef>(new Map()); - // Use React Query hook for fetching voucher data - const { data: voucherData, isLoading: isLoadingData, refetch: refetchVouchers, error: fetchError } = useVoucherRows({ rows: numberOfRows }); + // Use React Query hook for fetching voucher data - disabled by default + const { data: voucherData, isLoading: isLoadingData, refetch: refetchVouchers, error: fetchError } = useVoucherRows({ + rows: numberOfRows, + winner_number: selectedPrize + }, { + enabled: false // Disable automatic fetching - only fetch when Load Data is clicked + }); // Initialize Audio Context useEffect(() => { @@ -44,9 +52,9 @@ const RandomDrawApp: React.FC = () => { audioContextRef.current = new (window.AudioContext || (window as any).webkitAudioContext)(); } }; - + document.addEventListener('click', initAudio, { once: true }); - + return () => { document.removeEventListener('click', initAudio); tickIntervalRefs.current.forEach(timeout => clearTimeout(timeout)); @@ -57,21 +65,21 @@ const RandomDrawApp: React.FC = () => { // Create tick sound effect const playTickSound = () => { if (!audioContextRef.current) return; - + const ctx = audioContextRef.current; const oscillator = ctx.createOscillator(); const gainNode = ctx.createGain(); - + oscillator.connect(gainNode); gainNode.connect(ctx.destination); - + oscillator.frequency.setValueAtTime(800, ctx.currentTime); oscillator.frequency.exponentialRampToValueAtTime(200, ctx.currentTime + 0.05); - + gainNode.gain.setValueAtTime(0, ctx.currentTime); gainNode.gain.linearRampToValueAtTime(0.1, ctx.currentTime + 0.01); gainNode.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.05); - + oscillator.start(ctx.currentTime); oscillator.stop(ctx.currentTime + 0.05); }; @@ -79,12 +87,12 @@ const RandomDrawApp: React.FC = () => { // Create drum roll sound const playDrumRoll = () => { if (!audioContextRef.current) return; - + const ctx = audioContextRef.current; const oscillator = ctx.createOscillator(); const gainNode = ctx.createGain(); const noiseNode = ctx.createBufferSource(); - + // Create noise buffer for snare-like sound const bufferSize = ctx.sampleRate * 0.05; const buffer = ctx.createBuffer(1, bufferSize, ctx.sampleRate); @@ -93,15 +101,15 @@ const RandomDrawApp: React.FC = () => { data[i] = Math.random() * 2 - 1; } noiseNode.buffer = buffer; - + oscillator.connect(gainNode); noiseNode.connect(gainNode); gainNode.connect(ctx.destination); - + oscillator.frequency.setValueAtTime(200, ctx.currentTime); gainNode.gain.setValueAtTime(0.05, ctx.currentTime); gainNode.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + 0.1); - + oscillator.start(ctx.currentTime); oscillator.stop(ctx.currentTime + 0.1); noiseNode.start(ctx.currentTime); @@ -110,23 +118,23 @@ const RandomDrawApp: React.FC = () => { // Create winner sound const playWinnerSound = () => { if (!audioContextRef.current) return; - + const ctx = audioContextRef.current; const notes = [523.25, 659.25, 783.99, 1046.5]; // C, E, G, C (higher octave) - + notes.forEach((freq, index) => { const oscillator = ctx.createOscillator(); const gainNode = ctx.createGain(); - + oscillator.connect(gainNode); gainNode.connect(ctx.destination); - + oscillator.frequency.setValueAtTime(freq, ctx.currentTime + index * 0.1); - + gainNode.gain.setValueAtTime(0, ctx.currentTime + index * 0.1); gainNode.gain.linearRampToValueAtTime(0.2, ctx.currentTime + index * 0.1 + 0.05); gainNode.gain.exponentialRampToValueAtTime(0.001, ctx.currentTime + index * 0.1 + 0.5); - + oscillator.start(ctx.currentTime + index * 0.1); oscillator.stop(ctx.currentTime + index * 0.1 + 0.5); }); @@ -138,23 +146,23 @@ const RandomDrawApp: React.FC = () => { if (existingInterval) { clearTimeout(existingInterval); } - + let tickInterval = 50; const maxInterval = 200; const intervalIncrement = (maxInterval - tickInterval) / (duration / 100); - + const tick = () => { playTickSound(); tickInterval += intervalIncrement; - + if (tickInterval < maxInterval) { const timeoutId = setTimeout(tick, Math.min(tickInterval, maxInterval)); tickIntervalRefs.current.set(rowId, timeoutId); } }; - + tick(); - + setTimeout(() => { const interval = tickIntervalRefs.current.get(rowId); if (interval) { @@ -200,10 +208,7 @@ const RandomDrawApp: React.FC = () => { } }, [fetchError]); - // Refetch when numberOfRows changes - useEffect(() => { - refetchVouchers(); - }, [numberOfRows]); + // Remove auto-refetch - data will only load when Load Data button is clicked // Shuffle all rows (Acak functionality) const shuffleAllRows = () => { @@ -216,10 +221,10 @@ const RandomDrawApp: React.FC = () => { spinRows.forEach((row, index) => { let shuffleCount = 0; const maxShuffles = 20; - + const shuffleInterval = setInterval(() => { shuffleCount++; - + setSpinRows(prev => prev.map(r => { if (r.id === row.id) { return { @@ -229,9 +234,9 @@ const RandomDrawApp: React.FC = () => { } return r; })); - + playTickSound(); - + if (shuffleCount >= maxShuffles) { clearInterval(shuffleInterval); setTimeout(() => { @@ -247,7 +252,7 @@ const RandomDrawApp: React.FC = () => { }, index * 100); } }, 100); - + shuffleIntervalRefs.current.set(row.id, shuffleInterval as any); }); }; @@ -256,47 +261,47 @@ const RandomDrawApp: React.FC = () => { const revealWinnersDramatically = async () => { setIsRevealingWinners(true); setRevealedWinners(new Set()); - + // First, arrange winners to be in the winner zone for each row const arrangedRows = spinRows.map(row => { const winner = row.vouchers.find(v => v.is_winner); if (!winner) return row; - + // Create a new display order with winner at position 3 or 4 (will be in winner zone) const otherVouchers = row.vouchers.filter(v => v.voucher_code !== winner.voucher_code); const shuffledOthers = shuffleArray(otherVouchers); - + // Place winner at index 3 (4th position) which will be in the winner zone const newDisplayVouchers = [ ...shuffledOthers.slice(0, 3), winner, ...shuffledOthers.slice(3) ]; - + return { ...row, displayVouchers: newDisplayVouchers }; }); - + // Update display to show arranged vouchers setSpinRows(arrangedRows); - + // Start drum roll effect const drumRollInterval = setInterval(() => { playDrumRoll(); }, 100); - + // Create a scrolling/spinning effect for all wheels simultaneously let scrollSpeed = 50; let currentScroll = 0; const maxScroll = 2000; const deceleration = 0.95; - + const spinInterval = setInterval(() => { currentScroll += scrollSpeed; scrollSpeed *= deceleration; - + // Apply scrolling to all wheels arrangedRows.forEach(row => { const wheelElement = row.wheelRef.current; @@ -305,12 +310,12 @@ const RandomDrawApp: React.FC = () => { wheelElement.style.transform = `translateY(${-currentScroll}px)`; } }); - + // Stop when speed is very slow if (scrollSpeed < 0.5 || currentScroll >= maxScroll) { clearInterval(spinInterval); clearInterval(drumRollInterval); - + // Final positioning - snap to winner position arrangedRows.forEach(row => { const wheelElement = row.wheelRef.current; @@ -319,20 +324,20 @@ const RandomDrawApp: React.FC = () => { const WINNER_ZONE_TOP = 260; // Top position of winner zone // Position 4th card (index 3) exactly at the winner zone const finalPosition = -(3 * CARD_HEIGHT - WINNER_ZONE_TOP); - + wheelElement.style.transition = 'transform 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94)'; wheelElement.style.transform = `translateY(${finalPosition}px)`; } }); } }, 20); - + // Wait for scrolling to complete await new Promise(resolve => setTimeout(resolve, 3000)); - + // Play winner sound playWinnerSound(); - + // Collect all winners const winnersToReveal: { row: SpinRow, winner: Voucher }[] = []; arrangedRows.forEach(row => { @@ -341,11 +346,11 @@ const RandomDrawApp: React.FC = () => { winnersToReveal.push({ row, winner }); } }); - + // Update all winners at once with highlighting const allWinnerNumbers = new Set(); const historyEntries: WinnerHistory[] = []; - + winnersToReveal.forEach(({ row, winner }) => { allWinnerNumbers.add(row.rowNumber); historyEntries.push({ @@ -354,10 +359,10 @@ const RandomDrawApp: React.FC = () => { timestamp: new Date() }); }); - + // Update state to highlight winners setRevealedWinners(allWinnerNumbers); - + setSpinRows(prev => prev.map(r => { const winnerInfo = winnersToReveal.find(w => w.row.id === r.id); if (winnerInfo) { @@ -369,12 +374,112 @@ const RandomDrawApp: React.FC = () => { } return r; })); - + setWinnersHistory(prev => [...prev, ...historyEntries]); - + setIsRevealingWinners(false); }; + const performDramaticSpin = (row: SpinRow, isSequential: boolean = false) => { + const wheelElement = row.wheelRef.current; + if (!wheelElement) return; + + const winner = row.vouchers.find(v => v.is_winner); + if (!winner) { + console.error('No winner found in vouchers'); + return; + } + + const CARD_HEIGHT = 80; + const WINNER_ZONE_TOP = 260; // Top position of winner zone + + // Shuffle the display vouchers to create more dramatic effect + const shuffledVouchers = shuffleArray([...row.vouchers]); + const winnerIndex = shuffledVouchers.findIndex(v => v.voucher_code === winner.voucher_code); + + // Update display vouchers with shuffled order + setSpinRows(prev => prev.map(r => + r.id === row.id ? { ...r, displayVouchers: shuffledVouchers } : r + )); + + wheelElement.style.transition = 'none'; + wheelElement.style.transform = 'translateY(0px)'; + wheelElement.offsetHeight; + + setTimeout(() => { + // More dramatic spinning with multiple phases + const minSpins = 15; + const maxSpins = 25; + const spins = minSpins + Math.random() * (maxSpins - minSpins); + const totalItems = shuffledVouchers.length; + + const totalRotations = Math.floor(spins); + const baseScrollDistance = totalRotations * totalItems * CARD_HEIGHT; + const winnerScrollPosition = winnerIndex * CARD_HEIGHT; + const finalPosition = -(baseScrollDistance + winnerScrollPosition) + WINNER_ZONE_TOP; + + const distance = Math.abs(finalPosition); + const baseDuration = 4000; // Longer base duration + const maxDuration = 7000; // Longer max duration + const duration = Math.min(baseDuration + (distance / 8000) * 2000, maxDuration); + + // Phase 1: Fast initial spin + const phase1Duration = duration * 0.3; + const phase1Distance = finalPosition * 0.7; + + wheelElement.style.transform = `translateY(${phase1Distance}px)`; + wheelElement.style.transition = `transform ${phase1Duration}ms cubic-bezier(0.25, 0.46, 0.45, 0.94)`; + + // Phase 2: Slower approach to final position + setTimeout(() => { + wheelElement.style.transform = `translateY(${finalPosition}px)`; + wheelElement.style.transition = `transform ${duration - phase1Duration}ms cubic-bezier(0.17, 0.67, 0.12, 0.99)`; + }, phase1Duration); + + startTickSound(row.id, duration); + + setTimeout(() => { + const interval = tickIntervalRefs.current.get(row.id); + if (interval) { + clearTimeout(interval); + tickIntervalRefs.current.delete(row.id); + } + + playWinnerSound(); + + setSpinRows(prev => prev.map(r => + r.id === row.id + ? { ...r, isSpinning: false, winner: winner, selectedWinner: winner } + : r + )); + + setWinnersHistory(prev => [...prev, { + rowNumber: row.rowNumber, + winner: winner, + timestamp: new Date() + }]); + + // If this is sequential spinning, trigger next row + if (isSequential) { + const nextRowIndex = spinRows.findIndex(r => r.id === row.id) + 1; + if (nextRowIndex < spinRows.length) { + setTimeout(() => { + spinSequentialRow(nextRowIndex); + }, 2000); // Wait 2 seconds before next spin + } else { + // All rows completed + setIsSequentialSpinning(false); + setCurrentSpinningRow(null); + } + } + + // Keep the winner in the winner zone - don't reset position + // The winning card will stay exactly where it landed in the winner zone + + }, duration); + }, 100); + }; + const performSpin = (row: SpinRow) => { const wheelElement = row.wheelRef.current; if (!wheelElement) return; @@ -387,89 +492,113 @@ const RandomDrawApp: React.FC = () => { const CARD_HEIGHT = 80; const WINNER_ZONE_TOP = 260; // Top position of winner zone - - const winnerIndex = row.displayVouchers.findIndex(v => v.voucher_code === winner.voucher_code); - + + // Shuffle the display vouchers to create more dramatic effect + const shuffledVouchers = shuffleArray([...row.vouchers]); + const winnerIndex = shuffledVouchers.findIndex(v => v.voucher_code === winner.voucher_code); + + // Update display vouchers with shuffled order + setSpinRows(prev => prev.map(r => + r.id === row.id ? { ...r, displayVouchers: shuffledVouchers } : r + )); + wheelElement.style.transition = 'none'; wheelElement.style.transform = 'translateY(0px)'; wheelElement.offsetHeight; - + setTimeout(() => { - const minSpins = 10; - const maxSpins = 20; + // More dramatic spinning with multiple phases + const minSpins = 15; + const maxSpins = 25; const spins = minSpins + Math.random() * (maxSpins - minSpins); - const totalItems = row.displayVouchers.length; - + const totalItems = shuffledVouchers.length; + const totalRotations = Math.floor(spins); const baseScrollDistance = totalRotations * totalItems * CARD_HEIGHT; const winnerScrollPosition = winnerIndex * CARD_HEIGHT; const finalPosition = -(baseScrollDistance + winnerScrollPosition) + WINNER_ZONE_TOP; - + const distance = Math.abs(finalPosition); - const baseDuration = 3000; - const maxDuration = 5000; - const duration = Math.min(baseDuration + (distance / 10000) * 1000, maxDuration); - - wheelElement.style.transform = `translateY(${finalPosition}px)`; - wheelElement.style.transition = `transform ${duration}ms cubic-bezier(0.17, 0.67, 0.12, 0.99)`; - + const baseDuration = 4000; // Longer base duration + const maxDuration = 7000; // Longer max duration + const duration = Math.min(baseDuration + (distance / 8000) * 2000, maxDuration); + + // Phase 1: Fast initial spin + const phase1Duration = duration * 0.3; + const phase1Distance = finalPosition * 0.7; + + wheelElement.style.transform = `translateY(${phase1Distance}px)`; + wheelElement.style.transition = `transform ${phase1Duration}ms cubic-bezier(0.25, 0.46, 0.45, 0.94)`; + + // Phase 2: Slower approach to final position + setTimeout(() => { + wheelElement.style.transform = `translateY(${finalPosition}px)`; + wheelElement.style.transition = `transform ${duration - phase1Duration}ms cubic-bezier(0.17, 0.67, 0.12, 0.99)`; + }, phase1Duration); + startTickSound(row.id, duration); - + setTimeout(() => { const interval = tickIntervalRefs.current.get(row.id); if (interval) { clearTimeout(interval); tickIntervalRefs.current.delete(row.id); } - + playWinnerSound(); - - setSpinRows(prev => prev.map(r => - r.id === row.id + + setSpinRows(prev => prev.map(r => + r.id === row.id ? { ...r, isSpinning: false, winner: winner, selectedWinner: winner } : r )); - + setWinnersHistory(prev => [...prev, { rowNumber: row.rowNumber, winner: winner, timestamp: new Date() }]); - - setTimeout(() => { - wheelElement.style.transition = 'none'; - wheelElement.style.transform = 'translateY(0px)'; - wheelElement.offsetHeight; - }, 1500); - + + // Keep the winner in the winner zone - don't reset position + // The winning card will stay exactly where it landed in the winner zone + }, duration); }, 100); }; - const spinWheel = (rowId: string) => { - const row = spinRows.find(r => r.id === rowId); - if (!row || row.isSpinning || row.winner) return; - - setSpinRows(prev => prev.map(r => - r.id === rowId ? { ...r, isSpinning: true, selectedWinner: null } : r + const spinSequentialRow = (rowIndex: number) => { + if (rowIndex >= spinRows.length) { + setIsSequentialSpinning(false); + setCurrentSpinningRow(null); + return; + } + + const row = spinRows[rowIndex]; + if (!row || row.isSpinning || row.winner) { + // Skip this row and go to next + spinSequentialRow(rowIndex + 1); + return; + } + + setCurrentSpinningRow(row.rowNumber); + setSpinRows(prev => prev.map(r => + r.id === row.id ? { ...r, isSpinning: true, selectedWinner: null } : r )); - + const wheelElement = row.wheelRef.current; if (wheelElement) { wheelElement.style.transition = 'none'; wheelElement.style.transform = 'translateY(0px)'; wheelElement.offsetHeight; } - - performSpin(row); + + performDramaticSpin(row, true); }; - const clearResults = () => { - tickIntervalRefs.current.forEach(timeout => clearTimeout(timeout)); - shuffleIntervalRefs.current.forEach(timeout => clearTimeout(timeout)); - tickIntervalRefs.current.clear(); - shuffleIntervalRefs.current.clear(); - + const startSequentialSpinning = () => { + if (spinRows.length === 0) return; + + // Clear any existing results setWinnersHistory([]); setRevealedWinners(new Set()); setSpinRows(prev => prev.map(row => ({ @@ -480,7 +609,62 @@ const RandomDrawApp: React.FC = () => { selectedWinner: null, displayVouchers: [...row.vouchers] }))); - + + // Reset all wheel positions + spinRows.forEach(row => { + const wheelElement = row.wheelRef.current; + if (wheelElement) { + wheelElement.style.transition = 'none'; + wheelElement.style.transform = 'translateY(0px)'; + } + }); + + setIsSequentialSpinning(true); + setCurrentSpinningRow(null); + + // Start with first row after a short delay + setTimeout(() => { + spinSequentialRow(0); + }, 500); + }; + + const spinWheel = (rowId: string) => { + const row = spinRows.find(r => r.id === rowId); + if (!row || row.isSpinning || row.winner) return; + + setSpinRows(prev => prev.map(r => + r.id === rowId ? { ...r, isSpinning: true, selectedWinner: null } : r + )); + + const wheelElement = row.wheelRef.current; + if (wheelElement) { + wheelElement.style.transition = 'none'; + wheelElement.style.transform = 'translateY(0px)'; + wheelElement.offsetHeight; + } + + performSpin(row); + }; + + const clearResults = () => { + tickIntervalRefs.current.forEach(timeout => clearTimeout(timeout)); + shuffleIntervalRefs.current.forEach(timeout => clearTimeout(timeout)); + tickIntervalRefs.current.clear(); + shuffleIntervalRefs.current.clear(); + + setWinnersHistory([]); + setRevealedWinners(new Set()); + setIsSequentialSpinning(false); + setCurrentSpinningRow(null); + setSpinRows(prev => prev.map(row => ({ + ...row, + isSpinning: false, + isShuffling: false, + winner: null, + selectedWinner: null, + displayVouchers: [...row.vouchers] + }))); + spinRows.forEach(row => { const wheelElement = row.wheelRef.current; if (wheelElement) { @@ -495,7 +679,7 @@ const RandomDrawApp: React.FC = () => { shuffleIntervalRefs.current.forEach(timeout => clearTimeout(timeout)); tickIntervalRefs.current.clear(); shuffleIntervalRefs.current.clear(); - + try { await refetchVouchers(); toast.success('Data refreshed successfully'); @@ -527,97 +711,110 @@ const RandomDrawApp: React.FC = () => { opacity: 1; } } - + .animate-bounce-in { animation: bounce-in 0.6s ease-out; } `} - +
{/* Header */}

Voucher Lucky Draw

-

Select random winners from voucher database

-
- {/* Controls Section */} -
+
+ {/* Controls Section - Compact Layout */} +
{/* Configuration Card */} -
-

+
+

Configuration

- -
-
- - setNumberOfRows(parseInt(e.target.value) || 1)} - className="w-full bg-white border border-gray-300 rounded-lg p-2 text-gray-900 focus:border-primary focus:outline-none focus:ring-2 focus:ring-primary/20" - disabled={isLoadingData} - /> -
- - -
- - {spinRows.length > 0 && ( -
-
-
Rows: {spinRows.length}
-
Total Vouchers: {spinRows.reduce((acc, row) => acc + row.vouchers.length, 0)}
+ +
+
+
+ + setNumberOfRows(parseInt(e.target.value) || 1)} + className="w-full bg-white border border-gray-300 rounded p-1.5 text-sm text-gray-900 focus:border-primary focus:outline-none focus:ring-1 focus:ring-primary/20" + disabled={isLoadingData} + /> +
+ +
+ + +
+ + +
+ + {spinRows.length > 0 && ( +
+
Rows: {spinRows.length} | Vouchers: {spinRows.reduce((acc, row) => acc + row.vouchers.length, 0)}
)}
{/* Actions Card */} -
-

+
+

Actions

- -
+ +
- + - + {winnersHistory.length > 0 && ( )} @@ -625,18 +822,18 @@ const RandomDrawApp: React.FC = () => {
{/* Winners Summary Card */} -
-

- +
+

+ Winners

- + {winnersHistory.length > 0 ? ( -
+
{winnersHistory.map((history) => ( -
Row {history.rowNumber}: {history.winner.name} @@ -648,9 +845,9 @@ const RandomDrawApp: React.FC = () => { ))}
) : ( -
- -

No winners yet

+
+ +

No winners yet

)}
@@ -670,22 +867,7 @@ const RandomDrawApp: React.FC = () => { row.isShuffling ? 'border-purple-400 animate-pulse' : 'border-gray-200' }`}>
-
-

- Row {row.rowNumber} - ({row.vouchers.length}) -

- - -
- + {row.winner && (
@@ -700,54 +882,57 @@ const RandomDrawApp: React.FC = () => {
)}
- + {/* Wheel Container */} -
- {/* Winner Selection Zone - Exactly 80px matching card height */} -
-
- WINNER +
+
+ 🏆 WINNER +
{/* Scrolling Cards */} -
- {Array.from({ length: 50 }, (_, repeatIndex) => + {Array.from({ length: 50 }, (_, repeatIndex) => row.displayVouchers.map((voucher, voucherIndex) => { const isSelectedWinner = row.selectedWinner?.voucher_code === voucher.voucher_code; - + return ( -
+
{ {voucher.name}
- +
{formatPhoneNumber(voucher.phone_number)} @@ -774,7 +959,7 @@ const RandomDrawApp: React.FC = () => { }) )}
- + {/* Gradient Overlays */}
@@ -788,4 +973,4 @@ const RandomDrawApp: React.FC = () => { ); }; -export default RandomDrawApp; \ No newline at end of file +export default RandomDrawApp; diff --git a/src/services/queries/vouchers.ts b/src/services/queries/vouchers.ts index 1d4cdf4..a70feaf 100644 --- a/src/services/queries/vouchers.ts +++ b/src/services/queries/vouchers.ts @@ -4,28 +4,31 @@ import { api } from '../api' export interface VouchersQueryParams { rows?: number + winner_number?: number } -export function useVoucherRows(params: VouchersQueryParams = {}) { - const { rows = 4 } = params +export function useVoucherRows(params: VouchersQueryParams = {}, options: { enabled?: boolean } = {}) { + const { rows = 5, winner_number = 1 } = params + const { enabled = true } = options return useQuery({ - queryKey: ['voucher-rows', { rows }], + queryKey: ['voucher-rows', { rows, winner_number }], queryFn: async () => { const res = await api.get(`/vouchers/rows`, { - params: { rows } + params: { rows, winner_number } }) return res.data.data }, + enabled, staleTime: 5 * 60 * 1000, refetchOnWindowFocus: false }) } // Manual fetch function for cases where you need to fetch without using the hook -export async function fetchVoucherRows(rows: number = 4): Promise { +export async function fetchVoucherRows(rows: number = 5, winner_number: number = 1): Promise { const res = await api.get(`/vouchers/rows`, { - params: { rows } + params: { rows, winner_number } }) return res.data.data -} \ No newline at end of file +}