Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import { useState, useEffect } from 'react';
- import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
- import {
- faCoins,
- faTicket,
- faUsers,
- faInfo,
- faList,
- faTrophy
- } from '@fortawesome/free-solid-svg-icons';
- import { call, listen } from "@autumngmod/cream-api"
- const LotteryTab = () => {
- type Entry = {
- player_name: string;
- tickets: number
- };
- type Winner = {
- player_name: string;
- jackpot_won: number;
- date_won: number; // unix timestamp
- };
- const [localPlySteamId, setLocalPlySteamId] = useState<string | null>(null);
- const [ticketsToBuy, setTicketsToBuy] = useState(0);
- const [jackpot, setJackpot] = useState(0);
- const [entries, setEntries] = useState<Entry[]>([]);
- const [winners, setWinners] = useState<Winner[]>([]);
- const [loading, setLoading] = useState(true);
- const [error, setError] = useState<string | null>(null);
- // Fetch lottery data
- const fetchAndSetLotteryData = async () => {
- try {
- const baseUrl = 'https://giantslair.com';
- const response = await fetch(`${baseUrl}/gl/lottery/dumpjson`, {
- method: "GET",
- headers: {
- 'Accept': 'application/json',
- },
- });
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
- const contentType = response.headers.get('content-type');
- if (!contentType || !contentType.includes('application/json')) {
- throw new Error('API response is not JSON');
- }
- const data = await response.json();
- if (!data.entries || !data.history_winners || data.current_jackpot === undefined) {
- throw new Error('Invalid API response structure');
- }
- setJackpot(data.current_jackpot);
- setEntries(data.entries);
- setWinners(data.history_winners);
- setError(null);
- setLoading(false);
- // console.log('Lottery data fetched successfully:', { jackpot: data.current_jackpot, entries: data.entries, winners: data.history_winners });
- } catch (err) {
- console.error('Failed to fetch lottery data:', err);
- setError(err instanceof Error ? err.message : String(err));
- setLoading(false);
- }
- };
- // Fetch lottery data
- useEffect(() => {
- const fetchLotteryData = async () => {
- try {
- const baseUrl = 'https://giantslair.com';
- const response = await fetch(`${baseUrl}/gl/lottery/dumpjson`, {
- method: "GET",
- headers: {
- 'Accept': 'application/json',
- },
- });
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
- if (!response.ok) {
- throw new Error(`HTTP error! status: ${response.status}`);
- }
- const contentType = response.headers.get('content-type');
- if (!contentType || !contentType.includes('application/json')) {
- throw new Error('API response is not JSON');
- }
- const data = await response.json();
- // Validate response structure
- if (!data.entries || !data.history_winners || data.current_jackpot === undefined) {
- throw new Error('Invalid API response structure');
- }
- setJackpot(data.current_jackpot);
- setEntries(data.entries);
- setWinners(data.history_winners);
- setError(null);
- // console.log('Lottery data fetched successfully:', { jackpot: data.current_jackpot, entries: data.entries, winners: data.history_winners });
- } catch (err) {
- console.error('Failed to fetch lottery data:', err);
- setError(err instanceof Error ? err.message : String(err));
- } finally {
- setLoading(false);
- }
- };
- const getLocalPlySteamId = async () => {
- const steamid = await call("getLocalPlySteamId", 0);
- setLocalPlySteamId(String(steamid));
- };
- fetchLotteryData();
- getLocalPlySteamId();
- }, []);
- listen("refreshLotteryTab", () => {
- setLoading(true);
- fetchAndSetLotteryData();
- setTicketsToBuy(0);
- });
- // Calculate derived data
- const totalTickets = jackpot / 100; // Match Lua logic: total tickets in pool = jackpot / 100
- const playersEntered = entries.length;
- // Find our entry if we have tickets in the pool
- const ourEntry = localPlySteamId
- ? entries.find((entry: any) => entry.steamid === localPlySteamId)
- : undefined;
- const ourCurrentTickets = ourEntry ? ourEntry.tickets : 0;
- // Calculate user's chance based on current and to-buy tickets
- const newTotalTickets = totalTickets + ticketsToBuy;
- const yourTotalTickets = ourCurrentTickets + ticketsToBuy;
- const yourChance = newTotalTickets > 0
- ? Math.min((yourTotalTickets / newTotalTickets) * 100, 100)
- : 100;
- if (loading) {
- return (
- <div className="flex justify-center items-center h-64">
- <div className="text-gl-primary text-xl">Loading lottery data...</div>
- </div>
- );
- }
- if (error) {
- return (
- <div className="bg-red-900/30 border-l-4 border-red-500 p-4 rounded-r-lg my-8">
- <div className="flex items-start gap-2">
- <div className="w-5 h-5 bg-red-500 rounded-full flex items-center justify-center flex-shrink-0 mt-0.5">
- <FontAwesomeIcon icon={faInfo} className="text-white text-xs" />
- </div>
- <p className="text-red-200 text-sm leading-relaxed">
- Error loading lottery data: {error}
- </p>
- </div>
- </div>
- );
- }
- return (
- <div className="scrollable-content h-full">
- <div className="grid grid-cols-1 lg:grid-cols-3 gap-8 p-8">
- {/* Current Jackpot Section */}
- <div className="bg-gray-800/50 rounded-lg p-6 lg:col-span-1">
- <div className="flex items-center gap-3 mb-4">
- <div className="w-8 h-8 rounded-lg flex items-center justify-center">
- <FontAwesomeIcon icon={faCoins} className="w-6 h-6 text-gl-primary" />
- </div>
- <h2 className="text-xl font-semibold text-gray-300">Current Jackpot</h2>
- </div>
- <div className="text-6xl font-bold text-gl-primary mb-2">
- {jackpot.toLocaleString()}
- </div>
- <div className="text-gray-400 mb-8">Points</div>
- <div className="grid grid-cols-2 gap-6">
- <div className="text-center">
- <div className="w-12 h-12 bg-gl-secondary-light/20 rounded-lg flex items-center justify-center mx-auto mb-2">
- <FontAwesomeIcon icon={faTicket} className="w-8 h-8 text-gl-primary" />
- </div>
- <div className="text-2xl font-bold text-white">{totalTickets.toLocaleString()}</div>
- <div className="text-sm text-gray-400">Tickets in Pool</div>
- </div>
- <div className="text-center">
- <div className="w-12 h-12 bg-gl-secondary-light/20 rounded-lg flex items-center justify-center mx-auto mb-2">
- <FontAwesomeIcon icon={faUsers} className="w-8 h-8 text-gl-primary" />
- </div>
- <div className="text-2xl font-bold text-white">{playersEntered.toLocaleString()}</div>
- <div className="text-sm text-gray-400">Players Entered</div>
- </div>
- </div>
- </div>
- {/* Purchase Tickets Section */}
- <div className="bg-gray-800/50 rounded-lg p-6 flex flex-col lg:col-span-2">
- <div className="flex items-center gap-3 mb-4">
- <div className="w-8 h-8 rounded-lg flex items-center justify-center">
- <FontAwesomeIcon icon={faTicket} className="w-6 h-6 text-gl-primary" />
- </div>
- <h2 className="text-xl font-semibold text-gray-300">Purchase Tickets</h2>
- </div>
- <div className="grid grid-cols-2 gap-4 mb-6">
- <div>
- <label className="flex text-sm text-gray-400 mb-2">Your Chance</label>
- <span className="text-2xl font-bold text-gl-primary">{yourChance.toFixed(2)}%</span>
- </div>
- <div>
- <label className="flex text-sm text-gray-400 mb-2">Tickets to Buy</label>
- <div className="flex gap-2">
- <div className="bg-gray-700 rounded-lg px-4 py-3 text-center flex-1">
- <input
- type="number"
- value={ticketsToBuy}
- onChange={(e) => setTicketsToBuy(Math.max(0, parseInt(e.target.value) || 0))}
- className="bg-transparent text-2xl font-bold text-white text-center w-full outline-none"
- min="0"
- />
- </div>
- <div className="flex">
- <button
- onClick={() => setTicketsToBuy(prev => prev + 1)}
- className="bg-gray-600 hover:bg-gray-500 text-white text-sm px-3 py-2 rounded-l-lg border-r border-gray-500 transition-colors"
- >
- +1
- </button>
- <button
- onClick={() => setTicketsToBuy(prev => prev + 5)}
- className="bg-gray-600 hover:bg-gray-500 text-white text-sm px-3 py-2 border-r border-gray-500 transition-colors"
- >
- +5
- </button>
- <button
- onClick={() => setTicketsToBuy(prev => prev + 10)}
- className="bg-gray-600 hover:bg-gray-500 text-white text-sm px-3 py-2 border-r border-gray-500 transition-colors"
- >
- +10
- </button>
- <button
- onClick={() => setTicketsToBuy(0)}
- className="bg-gray-600 hover:bg-gray-500 text-white text-sm px-3 py-2 rounded-r-lg transition-colors"
- >
- Reset
- </button>
- </div>
- </div>
- </div>
- </div>
- <div className="mb-6">
- <button
- onClick={async () => {
- try {
- await call("purchaseLotteryTickets", ticketsToBuy);
- } catch (error) {
- console.error('Error purchasing tickets:', error);
- }
- }}
- disabled={ticketsToBuy <= 0}
- className="bg-gl-primary hover:bg-gl-primary-hover disabled:bg-gray-600 disabled:cursor-not-allowed text-white font-bold py-3 px-6 rounded-lg transition-colors"
- >
- Purchase {ticketsToBuy} Ticket{ticketsToBuy !== 1 ? 's' : ''} ({(ticketsToBuy * 100).toLocaleString()} points)
- </button>
- </div>
- <div className="mt-auto">
- <div className="border-l-4 border-gl-secondary bg-gl-secondary/10 p-4 rounded-r-lg">
- <div className="flex items-start gap-2">
- <div className="w-5 h-5 bg-gl-secondary rounded-full flex items-center justify-center flex-shrink-0 mt-0.5">
- <FontAwesomeIcon icon={faInfo} className="text-white text-sm" />
- </div>
- <p className="text-sm leading-relaxed text-gray-300">
- Lottery drawings are picked every day at <span className="text-gl-primary font-semibold">11:59PM EST</span> to determine a winner. One ticket is
- randomly picked and the winner is awarded the entire jackpot for the given day.
- </p>
- </div>
- </div>
- </div>
- </div>
- {/* Current Entries and Last 30 Days Winners Tables */}
- <div className="lg:col-span-3 grid grid-cols-1 lg:grid-cols-2 gap-8">
- {/* Current Entries Table */}
- <div className="bg-gray-800/50 rounded-lg p-6 flex flex-col h-full min-h-0">
- <h3 className="text-xl font-semibold text-gray-300 mb-6 flex items-center gap-3">
- <span className="w-8 h-8 rounded-lg flex items-center justify-center">
- <FontAwesomeIcon icon={faList} className="w-6 h-6 text-gl-primary" />
- </span>
- Current Entries
- </h3>
- <div className="space-y-4 scrollable-content flex-1 min-h-0" style={{maxHeight: 'calc(100vh - 70vh)'}}>
- <div className="flex justify-between items-center text-sm text-gray-400 pb-2 border-b border-gray-700">
- <span>Player</span>
- <span>Tickets Bought</span>
- </div>
- {entries.map((entry, index) => (
- <div key={index} className="flex justify-between items-center py-2">
- <div className="flex items-center gap-3">
- <div className="w-8 h-8 bg-gl-primary rounded-full flex items-center justify-center">
- <span className="text-sm font-medium text-white">
- {entry.player_name.charAt(0).toUpperCase()}
- </span>
- </div>
- <span className="text-white">{entry.player_name}</span>
- </div>
- <span className="text-gl-primary font-medium">
- {entry.tickets.toLocaleString()}
- </span>
- </div>
- ))}
- {entries.length === 0 && (
- <div className="text-center py-8 text-gray-400">
- No entries yet. Be the first to buy tickets!
- </div>
- )}
- </div>
- </div>
- {/* Last 30 Days Winners Table */}
- <div className="bg-gray-800/50 rounded-lg p-6 flex flex-col h-full min-h-0">
- <h3 className="text-xl font-semibold text-gray-300 mb-6 flex items-center gap-3">
- <span className="w-8 h-8 rounded-lg flex items-center justify-center">
- <FontAwesomeIcon icon={faTrophy} className="w-6 h-6 text-gl-primary" />
- </span>
- Last 30 Days Winners
- </h3>
- <div className="space-y-4 scrollable-content flex-1 min-h-0" style={{maxHeight: 'calc(100vh - 350px)'}}>
- <div className="flex justify-between items-center text-sm text-gray-400 pb-2 border-b border-gray-700">
- <span>Player</span>
- <span>Points Won</span>
- <span>Date</span>
- </div>
- {winners.map((winner, index) => (
- <div key={index} className="flex justify-between items-center py-2">
- <div className="flex items-center gap-3">
- <div className="w-8 h-8 bg-yellow-500 rounded-full flex items-center justify-center">
- <FontAwesomeIcon icon={faTrophy} className="text-yellow-900 text-xs" />
- </div>
- <span className="text-white">{winner.player_name}</span>
- </div>
- <span className="text-gl-primary font-medium">
- {winner.jackpot_won.toLocaleString()}
- </span>
- <span className="text-gray-400 text-sm">{
- new Date(winner.date_won * 1000).toLocaleDateString('en-US', {
- year: 'numeric', month: '2-digit', day: '2-digit'
- })
- }</span>
- </div>
- ))}
- {winners.length === 0 && (
- <div className="text-center py-8 text-gray-400">
- No recent winners to display.
- </div>
- )}
- </div>
- </div>
- </div>
- </div>
- </div>
- );
- };
- export default LotteryTab;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement