= (
| {props.index + 1} |
{props.standing.participation.team.logo && (
-
)}
diff --git a/components/matchs/TimelineItem.tsx b/components/matchs/TimelineItem.tsx
index 7d1cb9f..e8f2dfe 100644
--- a/components/matchs/TimelineItem.tsx
+++ b/components/matchs/TimelineItem.tsx
@@ -25,7 +25,7 @@ export const TimelineItem: React.FC = ({ event }) => {
{event.minute}
- {event.stoppage_minute ? `+${event.stoppage_minute}` : ""}'
+ {event.stoppage_minute ? `+${event.stoppage_minute}` : ""}'
diff --git a/components/players/PlayerTeams.tsx b/components/players/PlayerTeams.tsx
index 97ef23c..360c6cb 100644
--- a/components/players/PlayerTeams.tsx
+++ b/components/players/PlayerTeams.tsx
@@ -4,6 +4,7 @@ import React, { useEffect, useState } from "react";
import { PlayerService } from "@/services/PlayerService";
import { IPlayer, IPlayerTeamHistory } from "@/interfaces/IPlayers";
import { Loader2 } from "lucide-react";
+import Image from "next/image";
interface IPlayerTeamsProps {
player: IPlayer;
@@ -61,9 +62,11 @@ export const PlayerTeams: React.FC = ({ player }) => {
className="flex items-center gap-4 border rounded-lg p-4 shadow-sm hover:shadow-md transition"
>
{h.team.logo && (
-
)}
diff --git a/components/players/PlayerTransferts.tsx b/components/players/PlayerTransferts.tsx
index 2cf4a13..32c089b 100644
--- a/components/players/PlayerTransferts.tsx
+++ b/components/players/PlayerTransferts.tsx
@@ -6,6 +6,7 @@ import { IPlayer } from "@/interfaces/IPlayers";
import { IPlayerTransfers } from "@/interfaces/ITransfers";
import { Loader2 } from "lucide-react";
import { ArrowRight } from "lucide-react";
+import Image from "next/image";
interface IPlayerTransfertsProps {
player: IPlayer;
@@ -59,9 +60,11 @@ export const PlayerTransferts: React.FC = ({
{/* From team */}
{t.team?.logo && (
- 
)}
@@ -76,9 +79,11 @@ export const PlayerTransferts: React.FC = ({
{/* To team */}
{t.team?.logo && (
- 
)}
diff --git a/components/standings/StandingDataTable.tsx b/components/standings/StandingDataTable.tsx
index 15be8fb..653ae8b 100644
--- a/components/standings/StandingDataTable.tsx
+++ b/components/standings/StandingDataTable.tsx
@@ -1,4 +1,6 @@
-import React from "react";
+"use client";
+
+import React, { useMemo } from "react";
import {
ColumnDef,
flexRender,
@@ -21,60 +23,62 @@ interface IDataTableProps {
standings: IStanding[];
}
-export const StandingDataTable: React.FC = (
- props: IDataTableProps
-) => {
+export const StandingDataTable: React.FC = ({
+ columns: propColumns,
+ standings,
+}) => {
+ const columns = useMemo(() => propColumns, [propColumns]);
+
+ const data = useMemo(() => [...standings].sort(standingSort), [standings]);
+
const table = useReactTable({
- data: props.standings.sort(standingSort),
- columns: props.columns,
+ data,
+ columns,
getCoreRowModel: getCoreRowModel(),
});
return (
-
-
- {table.getHeaderGroups().map((headerGroup) => (
-
- {headerGroup.headers.map((header) => {
- return (
+
+
+
+ {table.getHeaderGroups().map((headerGroup) => (
+
+ {headerGroup.headers.map((header) => (
{header.isPlaceholder
? null
: flexRender(
header.column.columnDef.header,
- header.getContext()
+ header.getContext(),
)}
- );
- })}
-
- ))}
-
-
- {table.getRowModel().rows?.length ? (
- table.getRowModel().rows.map((row) => (
-
- {row.getVisibleCells().map((cell) => (
-
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
-
))}
- ))
- ) : (
-
-
- No results.
-
-
- )}
-
-
+ ))}
+
+
+ {table.getRowModel().rows?.length ? (
+ table.getRowModel().rows.map((row) => (
+
+ {row.getVisibleCells().map((cell) => (
+
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
+
+ ))}
+
+ ))
+ ) : (
+
+
+ No results.
+
+
+ )}
+
+
+
);
};
diff --git a/components/teams/ChampionshipTeamList.tsx b/components/teams/ChampionshipTeamList.tsx
index 18c0fab..6cdc8d4 100644
--- a/components/teams/ChampionshipTeamList.tsx
+++ b/components/teams/ChampionshipTeamList.tsx
@@ -31,9 +31,6 @@ export const ChampionshipTeamList: React.FC = ({
return (
-
- {championship.name}'s Teams
-
{teams.map((team) => (
= ({
- columns,
- data,
+ columns: propColumns,
+ data: propData,
}) => {
const [sorting, setSorting] = useState([]);
+ const columns = useMemo(() => propColumns, [propColumns]);
+
+ const data = useMemo(() => propData, [propData]);
+
const table = useReactTable({
data,
columns,
@@ -42,9 +46,10 @@ export const TeamStatDataTable: React.FC = ({
debugTable: false,
});
- const renderSortingIcon = (column: any) => {
+ const renderSortingIcon = (column: Column) => {
if (!column.getCanSort() || ["position", "team"].includes(column.id))
return null;
+
const sorted = column.getIsSorted();
if (sorted === "asc") return ;
if (sorted === "desc") return ;
@@ -65,7 +70,7 @@ export const TeamStatDataTable: React.FC = ({
>
{flexRender(
header.column.columnDef.header,
- header.getContext()
+ header.getContext(),
)}
{renderSortingIcon(header.column)}
@@ -75,15 +80,23 @@ export const TeamStatDataTable: React.FC = ({
- {table.getRowModel().rows.map((row) => (
-
- {row.getVisibleCells().map((cell) => (
-
- {flexRender(cell.column.columnDef.cell, cell.getContext())}
-
- ))}
+ {table.getRowModel().rows.length ? (
+ table.getRowModel().rows.map((row) => (
+
+ {row.getVisibleCells().map((cell) => (
+
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
+
+ ))}
+
+ ))
+ ) : (
+
+
+ No results.
+
- ))}
+ )}
diff --git a/constants/urls.ts b/constants/urls.ts
index a9366c2..999fbf8 100644
--- a/constants/urls.ts
+++ b/constants/urls.ts
@@ -3,7 +3,7 @@ if (!process.env.NEXT_PUBLIC_API_HOST) {
}
export const HOST = process.env.NEXT_PUBLIC_API_HOST;
-export let PROTOCOLE: string =
+export const PROTOCOLE: string =
process.env.NODE_ENV === "production" ? "https" : "http";
const API_VERSION = process.env.NEXT_PUBLIC_API_VERSION ?? "v1";
@@ -42,6 +42,7 @@ export const URLs = {
BY_EDITION: `${BASE_URL}/matchs/edition/$editionId/`,
APPEARANCE: `${BASE_URL}/appearances/match/$matchId/`,
SUBTITUTIONS: `${BASE_URL}/matchs/$matchId/substitutions/`,
+ LINEUPS: `${BASE_URL}/lineups/match/$matchId/`,
},
PLAYERS: {
ALL: `${BASE_URL}/players/`,
diff --git a/contexts/DeviceContext.tsx b/contexts/DeviceContext.tsx
deleted file mode 100644
index 50a4500..0000000
--- a/contexts/DeviceContext.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-import React, { createContext, useContext, useEffect, useState } from "react";
-import { getDeviceId } from "@/utils/device";
-import { NotificationService } from "@/services/NotificationService";
-import { WSClient } from "@/services/wsClient";
-import { URLs } from "@/constants/urls";
-
-interface DeviceContextValue {
- deviceId: string | null;
- ws: WSClient | null;
- connected: boolean;
-}
-
-const DeviceContext = createContext ({
- deviceId: null,
- ws: null,
- connected: false,
-});
-
-export const useDevice = () => useContext(DeviceContext);
-
-export const DeviceProvider: React.FC<{ children: React.ReactNode }> = ({
- children,
-}) => {
- const [deviceId, setDeviceId] = useState(null);
- const [connected, setConnected] = useState(false);
- const [wsClient, setWsClient] = useState(null);
-
- useEffect(() => {
- const initializeDeviceId = async () => {
- let currentId = getDeviceId();
-
- if (!currentId) {
- try {
- currentId = await NotificationService.registerDeviceOnServer();
- } catch (error) {
- console.error("Failed to register device:", error);
- }
- }
-
- if (currentId) {
- setDeviceId(currentId);
- }
- };
-
- initializeDeviceId();
- }, []);
-
- useEffect(() => {
- if (!deviceId) return;
-
- const client = new WSClient({
- url: URLs.NOTIFICATIONS.WEBSOCKET.replace("$deviceId", deviceId),
- reconnectInterval: 1000,
- maxReconnectInterval: 30000,
- reconnectDecay: 1.5,
- heartbeatInterval: 25000,
- onOpen: () => setConnected(true),
- onClose: () => setConnected(false),
- });
-
- client.on("message", (msg: any) => {
- if (typeof window !== "undefined") {
- window.dispatchEvent(
- new CustomEvent("notifications.ws.message", { detail: msg })
- );
- }
- });
-
- setWsClient(client);
-
- return () => {
- client.close();
- setConnected(false);
- setWsClient(null);
- };
- }, [deviceId]);
-
- return (
-
- {children}
-
- );
-};
diff --git a/contexts/NotificationsContext.tsx b/contexts/NotificationsContext.tsx
deleted file mode 100644
index afcae19..0000000
--- a/contexts/NotificationsContext.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import React, {
- createContext,
- useContext,
- useEffect,
- useRef,
- useState,
- ReactNode,
-} from "react";
-import { URLs } from "@/constants/urls";
-import { getDeviceId } from "@/utils/device";
-
-export interface NotificationPayload {
- id?: string;
- title: string;
- message: string;
- created_at?: string;
- type?: string;
-}
-
-interface NotificationContextType {
- notifications: NotificationPayload[];
-}
-
-const NotificationContext = createContext(
- undefined
-);
-
-interface ProviderProps {
- children: ReactNode;
-}
-
-export const NotificationProvider: React.FC = ({ children }) => {
- const [notifications, setNotifications] = useState([]);
- const wsRef = useRef(null);
-
- useEffect(() => {
- connectWebSocket();
-
- return () => {
- wsRef.current?.close();
- };
- }, []);
-
- const connectWebSocket = () => {
- const deviceId = getDeviceId();
- if (deviceId) {
- wsRef.current = new WebSocket(
- URLs.NOTIFICATIONS.WEBSOCKET.replace("$deviceId", deviceId)
- );
-
- wsRef.current.onopen = () => {
- console.log("WebSocket connected");
- };
-
- wsRef.current.onmessage = (event: MessageEvent) => {
- try {
- const data = JSON.parse(event.data);
- setNotifications((prev) => [...prev, data]);
- } catch (err) {
- console.error("Invalid WS notification data:", err);
- }
- };
-
- wsRef.current.onclose = () => {
- console.log("WebSocket disconnected… reconnecting");
- setTimeout(connectWebSocket, 2000);
- };
-
- wsRef.current.onerror = (err) => {
- console.error("WebSocket error", err);
- wsRef.current?.close();
- };
- }
- };
-
- return (
-
- {children}
-
- );
-};
-
-export const useNotifications = () => {
- const context = useContext(NotificationContext);
- if (!context)
- throw new Error(
- "useNotifications must be used inside NotificationProvider"
- );
- return context;
-};
diff --git a/interfaces/IMatch.d.ts b/interfaces/IMatch.d.ts
index 9bdd25c..b9c7308 100644
--- a/interfaces/IMatch.d.ts
+++ b/interfaces/IMatch.d.ts
@@ -12,6 +12,16 @@ interface IMatchTeam {
logo: string;
}
+interface IMatchLineUp {
+ id: number,
+ player: IBasePlayer;
+ team: ITeamBase,
+ match: number,
+ poistion: string;
+ is_starting: boolean;
+ minutes_played: number;
+}
+
export interface IMatchBase {
id: number;
type: MatchType;
@@ -43,16 +53,7 @@ export interface IMatch extends IMatchBase {
goals: IGoal[];
cards: ICard[];
substitutions: ISubtitution[];
-}
-
-
-export interface IMatchAppearance {
- id: number;
- player: IBasePlayer;
- team: ITeamBase;
- position: string;
- is_starting: boolean;
- minutesPlayed: number;
+ lineups: IMatchLineUp[];
}
diff --git a/services/MatchService.ts b/services/MatchService.ts
index 4ce315b..b26b40a 100644
--- a/services/MatchService.ts
+++ b/services/MatchService.ts
@@ -1,18 +1,23 @@
import { URLs } from "../constants/urls";
-import { IMatchBase, IMatch, IMatchAppearance, IMatchEvent } from "@/interfaces/IMatch";
+import {
+ IMatchBase,
+ IMatch,
+ IMatchEvent,
+ IMatchLineUp,
+} from "@/interfaces/IMatch";
export class MatchService {
public static async getMatchsByDay(date: Date): Promise {
const response = await fetch(
URLs.MATCHS.BY_DAY +
- `?date=${date.getDate()}-${date.getMonth() + 1}-${date.getFullYear()}`
+ `?date=${date.getDate()}-${date.getMonth() + 1}-${date.getFullYear()}`,
);
return response.json() as Promise;
}
public static async getMatchById(matchId: number): Promise {
const response = await fetch(
- URLs.MATCHS.BY_ID.replace("$id", matchId.toString())
+ URLs.MATCHS.BY_ID.replace("$id", matchId.toString()),
);
return response.json() as Promise;
}
@@ -20,11 +25,11 @@ export class MatchService {
public static async getMatchsByChampionshipEdition(
championshipId: number,
editionId: number,
- status: string = ""
+ status: string = "",
): Promise {
let url: string = URLs.MATCHS.BY_CHAMPIONSHIP_EDITION.replace(
"$championshipId",
- championshipId.toString()
+ championshipId.toString(),
).replace("$editionId", editionId.toString());
if (status !== "") {
url += `?status=${status}`;
@@ -35,11 +40,11 @@ export class MatchService {
public static async getMatchsByEdition(
editionId: number,
- status: string = ""
+ status: string = "",
): Promise {
let url: string = URLs.MATCHS.BY_EDITION.replace(
"$editionId",
- editionId.toString()
+ editionId.toString(),
);
if (status !== "") {
url += `?status=${status}`;
@@ -50,7 +55,7 @@ export class MatchService {
public static async getMatchsByTeam(
teamId: number,
- status: string = ""
+ status: string = "",
): Promise {
let url: string = URLs.MATCHS.BY_TEAM.replace("$teamId", teamId.toString());
if (status !== "") {
@@ -60,24 +65,26 @@ export class MatchService {
return response.json() as Promise;
}
- public static async getMatchAppearances(
- matchId: number
- ): Promise {
- const response = await fetch(
- URLs.MATCHS.APPEARANCE.replace("$matchId", matchId.toString())
+ public static async getMatchLineUp(matchId: number): Promise {
+ const url: string = URLs.MATCHS.LINEUPS.replace(
+ "$matchId",
+ matchId.toString(),
);
- return response.json() as Promise;
+ const response = await fetch(url);
+ return response.json() as Promise;
}
- public static async getMatchTimeline(_matchId: number): Promise{
+ public static async getMatchTimeline(
+ _matchId: number,
+ ): Promise {
+ console.log(_matchId);
return [];
}
- public static async getUpcomingMatchs(limit: number = 10): Promise{
- const response = await fetch(
- URLs.MATCHS.UPCOMING +
- `?limit=${limit}`
- );
+ public static async getUpcomingMatchs(
+ limit: number = 10,
+ ): Promise {
+ const response = await fetch(URLs.MATCHS.UPCOMING + `?limit=${limit}`);
return response.json() as Promise;
}
}
diff --git a/services/NotificationService.ts b/services/NotificationService.ts
deleted file mode 100644
index 20aece2..0000000
--- a/services/NotificationService.ts
+++ /dev/null
@@ -1,23 +0,0 @@
-import { URLs } from "@/constants/urls";
-
-
-export class NotificationService {
- public static async registerDeviceOnServer(): Promise {
- try {
- const res = await fetch(URLs.DEVICES.REGISTER, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({}),
- });
-
- if (!res.ok) {
- console.warn("Device registration returned non-OK:", res.status);
- }
- const data = await res.json() as {device_id: string}
- return data.device_id;
- } catch (err) {
- console.warn("Device registration error:", err);
- return "";
- }
- }
-}
diff --git a/services/wsClient.ts b/services/wsClient.ts
deleted file mode 100644
index a953899..0000000
--- a/services/wsClient.ts
+++ /dev/null
@@ -1,155 +0,0 @@
-import { BrowserEmitter } from "@/utils/BrowserEmitter";
-
-export type WSMessage = any;
-
-export interface WSClientOptions {
- url: string;
- protocols?: string | string[];
- reconnectInterval?: number; // initial ms
- maxReconnectInterval?: number;
- reconnectDecay?: number;
- heartbeatInterval?: number;
- onOpen?: () => void;
- onClose?: () => void;
- onMessage?: (msg: WSMessage) => void;
-}
-
-export class WSClient extends BrowserEmitter {
- private url: string;
- private protocols?: string | string[];
- private ws?: WebSocket | null;
- private reconnectInterval: number;
- private maxReconnectInterval: number;
- private reconnectDecay: number;
- private heartbeatInterval: number;
- private heartbeatTimer?: number | null;
- private reconnectTimer?: number | null;
- private shouldReconnect = true;
- private connected = false;
- private onOpen?: () => void;
- private onClose?: () => void;
- private onMessage?: (msg: WSMessage) => void;
-
- constructor(opts: WSClientOptions) {
- super();
- this.url = opts.url;
- this.protocols = opts.protocols;
- this.reconnectInterval = opts.reconnectInterval ?? 1000; // 1s
- this.maxReconnectInterval = opts.maxReconnectInterval ?? 30000; // 30s
- this.reconnectDecay = opts.reconnectDecay ?? 1.5;
- this.heartbeatInterval = opts.heartbeatInterval ?? 25000; // 25s
- this.onOpen = opts.onOpen;
- this.onClose = opts.onClose;
- this.onMessage = opts.onMessage;
- this.connect();
- }
-
- private connect() {
- this.clearTimers();
- try {
- this.ws = new WebSocket(this.url, this.protocols ?? undefined);
- } catch (err) {
- this.scheduleReconnect();
- return;
- }
-
- this.ws.onopen = () => {
- this.connected = true;
- this.emit("open");
- this.onOpen?.();
- this.startHeartbeat();
- };
-
- this.ws.onmessage = (ev) => {
- let data: any = ev.data;
- try {
- data = JSON.parse(ev.data);
- } catch {
- // keep raw
- }
- this.emit("message", data);
- this.onMessage?.(data);
- };
-
- this.ws.onclose = (ev) => {
- this.connected = false;
- this.emit("close", ev);
- this.onClose?.();
- if (this.shouldReconnect) this.scheduleReconnect();
- };
-
- this.ws.onerror = (ev) => {
- this.emit("error", ev);
- // underlying socket will call onclose, schedule reconnect there
- };
- }
-
- private startHeartbeat() {
- this.stopHeartbeat();
- this.heartbeatTimer = window.setInterval(() => {
- try {
- if (this.ws && this.ws.readyState === WebSocket.OPEN) {
- // send ping frame as JSON {type: 'ping'}
- this.ws.send(JSON.stringify({ type: "ping", ts: Date.now() }));
- } else {
- // not open, reconnect
- this.scheduleReconnect();
- }
- } catch {
- this.scheduleReconnect();
- }
- }, this.heartbeatInterval);
- }
-
- private stopHeartbeat() {
- if (this.heartbeatTimer) {
- window.clearInterval(this.heartbeatTimer);
- this.heartbeatTimer = null;
- }
- }
-
- private scheduleReconnect() {
- // compute next interval
- const next = Math.min(
- this.reconnectInterval * this.reconnectDecay,
- this.maxReconnectInterval
- );
- this.reconnectInterval = next;
- this.clearTimers();
- // schedule reconnect
- this.reconnectTimer = window.setTimeout(() => {
- this.connect();
- }, next);
- }
-
- private clearTimers() {
- if (this.reconnectTimer) {
- window.clearTimeout(this.reconnectTimer);
- this.reconnectTimer = null;
- }
- }
-
- public send(data: any) {
- if (this.ws && this.ws.readyState === WebSocket.OPEN) {
- const payload = typeof data === "string" ? data : JSON.stringify(data);
- this.ws.send(payload);
- } else {
- throw new Error("WebSocket not open");
- }
- }
-
- public close() {
- this.shouldReconnect = false;
- this.stopHeartbeat();
- if (this.ws) {
- try {
- this.ws.close();
- } catch {}
- }
- this.clearTimers();
- }
-
- public isConnected() {
- return this.connected;
- }
-}
diff --git a/tailwind.config.js b/tailwind.config.js
index ed6c49f..98d7936 100644
--- a/tailwind.config.js
+++ b/tailwind.config.js
@@ -1,84 +1,85 @@
/** @type {import('tailwindcss').Config} */
+import tailwindcssAnimate from "tailwindcss-animate";
+
export default {
- darkMode: ["class"],
- content: [
+ darkMode: ["class"],
+ content: [
"./app/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
"./pages/**/*.{js,ts,jsx,tsx}",
],
theme: {
- extend: {
- borderRadius: {
- lg: 'var(--radius)',
- md: 'calc(var(--radius) - 2px)',
- sm: 'calc(var(--radius) - 4px)'
- },
- colors: {
- background: 'hsl(var(--background))',
- foreground: 'hsl(var(--foreground))',
- card: {
- DEFAULT: 'hsl(var(--card))',
- foreground: 'hsl(var(--card-foreground))'
- },
- popover: {
- DEFAULT: 'hsl(var(--popover))',
- foreground: 'hsl(var(--popover-foreground))'
- },
- primary: {
- DEFAULT: 'hsl(var(--primary))',
- foreground: 'hsl(var(--primary-foreground))'
- },
- secondary: {
- DEFAULT: 'hsl(var(--secondary))',
- foreground: 'hsl(var(--secondary-foreground))'
- },
- muted: {
- DEFAULT: 'hsl(var(--muted))',
- foreground: 'hsl(var(--muted-foreground))'
- },
- accent: {
- DEFAULT: 'hsl(var(--accent))',
- foreground: 'hsl(var(--accent-foreground))'
- },
- destructive: {
- DEFAULT: 'hsl(var(--destructive))',
- foreground: 'hsl(var(--destructive-foreground))'
- },
- border: 'hsl(var(--border))',
- input: 'hsl(var(--input))',
- ring: 'hsl(var(--ring))',
- chart: {
- '1': 'hsl(var(--chart-1))',
- '2': 'hsl(var(--chart-2))',
- '3': 'hsl(var(--chart-3))',
- '4': 'hsl(var(--chart-4))',
- '5': 'hsl(var(--chart-5))'
- }
- },
- keyframes: {
- 'accordion-down': {
- from: {
- height: '0'
- },
- to: {
- height: 'var(--radix-accordion-content-height)'
- }
- },
- 'accordion-up': {
- from: {
- height: 'var(--radix-accordion-content-height)'
- },
- to: {
- height: '0'
- }
- }
- },
- animation: {
- 'accordion-down': 'accordion-down 0.2s ease-out',
- 'accordion-up': 'accordion-up 0.2s ease-out'
- }
- }
+ extend: {
+ borderRadius: {
+ lg: "var(--radius)",
+ md: "calc(var(--radius) - 2px)",
+ sm: "calc(var(--radius) - 4px)",
+ },
+ colors: {
+ background: "hsl(var(--background))",
+ foreground: "hsl(var(--foreground))",
+ card: {
+ DEFAULT: "hsl(var(--card))",
+ foreground: "hsl(var(--card-foreground))",
+ },
+ popover: {
+ DEFAULT: "hsl(var(--popover))",
+ foreground: "hsl(var(--popover-foreground))",
+ },
+ primary: {
+ DEFAULT: "hsl(var(--primary))",
+ foreground: "hsl(var(--primary-foreground))",
+ },
+ secondary: {
+ DEFAULT: "hsl(var(--secondary))",
+ foreground: "hsl(var(--secondary-foreground))",
+ },
+ muted: {
+ DEFAULT: "hsl(var(--muted))",
+ foreground: "hsl(var(--muted-foreground))",
+ },
+ accent: {
+ DEFAULT: "hsl(var(--accent))",
+ foreground: "hsl(var(--accent-foreground))",
+ },
+ destructive: {
+ DEFAULT: "hsl(var(--destructive))",
+ foreground: "hsl(var(--destructive-foreground))",
+ },
+ border: "hsl(var(--border))",
+ input: "hsl(var(--input))",
+ ring: "hsl(var(--ring))",
+ chart: {
+ 1: "hsl(var(--chart-1))",
+ 2: "hsl(var(--chart-2))",
+ 3: "hsl(var(--chart-3))",
+ 4: "hsl(var(--chart-4))",
+ 5: "hsl(var(--chart-5))",
+ },
+ },
+ keyframes: {
+ "accordion-down": {
+ from: {
+ height: "0",
+ },
+ to: {
+ height: "var(--radix-accordion-content-height)",
+ },
+ },
+ "accordion-up": {
+ from: {
+ height: "var(--radix-accordion-content-height)",
+ },
+ to: {
+ height: "0",
+ },
+ },
+ },
+ animation: {
+ "accordion-down": "accordion-down 0.2s ease-out",
+ "accordion-up": "accordion-up 0.2s ease-out",
+ },
+ },
},
- plugins: [require("tailwindcss-animate")],
-}
-
+ plugins: [tailwindcssAnimate],
+};
diff --git a/utils/BrowserEmitter.ts b/utils/BrowserEmitter.ts
deleted file mode 100644
index ea705e9..0000000
--- a/utils/BrowserEmitter.ts
+++ /dev/null
@@ -1,20 +0,0 @@
-export type Listener = (...args: any[]) => void;
-
-export class BrowserEmitter {
- private events: Record = {};
-
- on(event: string, listener: Listener) {
- if (!this.events[event]) this.events[event] = [];
- this.events[event].push(listener);
- }
-
- off(event: string, listener: Listener) {
- if (!this.events[event]) return;
- this.events[event] = this.events[event].filter((l) => l !== listener);
- }
-
- emit(event: string, ...args: any[]) {
- if (!this.events[event]) return;
- this.events[event].forEach((l) => l(...args));
- }
-}
diff --git a/utils/device.ts b/utils/device.ts
deleted file mode 100644
index 90f7deb..0000000
--- a/utils/device.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { DEVICE_KEY } from "@/constants/commons";
-
-export function getDeviceId(): string {
- let deviceId = localStorage.getItem(DEVICE_KEY);
- if (!deviceId) {
- return "";
- }
- return deviceId as string;
-}
-
-export function clearDeviceId() {
- localStorage.removeItem(DEVICE_KEY);
-}
|