diff --git a/.env.example b/.env.example index 80fd7d72..ed218ea2 100644 --- a/.env.example +++ b/.env.example @@ -9,6 +9,5 @@ NEXT_PUBLIC_ATHLONIX_STORAGE_URL= SUPABASE_DOMAIN= ATHLONIX_API_URL= NEXT_PUBLIC_API_URL= - STRIPE_API_KEY=sk_test_xxx STRIPE_WEBHOOK_SECRET=whsec_xxx diff --git a/apps/admin/Dockerfile b/apps/admin/Dockerfile index 1d240bbc..1b93f633 100644 --- a/apps/admin/Dockerfile +++ b/apps/admin/Dockerfile @@ -41,7 +41,8 @@ ENV NEXT_PUBLIC_ATHLONIX_STORAGE_URL ${NEXT_PUBLIC_ATHLONIX_STORAGE_URL} COPY --from=pruner --chown=node:node /app/out/full/ ./ RUN pnpm turbo run build --filter admin && \ - pnpm prune --prod + pnpm prune --prod && \ + pnpm --filter admin deploy --prod --ignore-scripts ./out FROM base AS dev WORKDIR /app diff --git a/apps/api/package.json b/apps/api/package.json index 7b3cb7c6..47ddea0d 100644 --- a/apps/api/package.json +++ b/apps/api/package.json @@ -17,7 +17,7 @@ "dependencies": { "@hono/node-server": "^1.11.2", "@hono/swagger-ui": "^0.2.2", - "@hono/zod-openapi": "0.14.1", + "@hono/zod-openapi": "0.14.2", "@hono/zod-validator": "^0.2.2", "@repo/types": "workspace:*", "@supabase/supabase-js": "^2.43.4", diff --git a/apps/client/Dockerfile b/apps/client/Dockerfile index 22416d23..554e754f 100644 --- a/apps/client/Dockerfile +++ b/apps/client/Dockerfile @@ -41,7 +41,8 @@ ENV NEXT_PUBLIC_ATHLONIX_STORAGE_URL ${NEXT_PUBLIC_ATHLONIX_STORAGE_URL} COPY --from=pruner --chown=node:node /app/out/full/ ./ RUN pnpm turbo run build --filter client && \ - pnpm prune --prod + pnpm prune --prod && \ + pnpm --filter client deploy --prod --ignore-scripts ./out FROM base AS dev WORKDIR /app diff --git a/apps/client/app/(auth)/(members)/members/layout.tsx b/apps/client/app/(auth)/(members)/members/layout.tsx new file mode 100644 index 00000000..e38f2588 --- /dev/null +++ b/apps/client/app/(auth)/(members)/members/layout.tsx @@ -0,0 +1,75 @@ +import '@repo/ui/globals.css'; +import { FileSearch, Flame, Home, LineChart, MessageSquareMore, Trophy, Users } from 'lucide-react'; +import Link from 'next/link'; + +export default function RootLayout({ + children, +}: { + children: React.ReactNode; +}): JSX.Element { + return ( + + +
+
+
+
+ + + Escape membre Athlonix + +
+
+ +
+
+
+
{children}
+
+ + + ); +} diff --git a/apps/client/app/(auth)/(members)/members/page.tsx b/apps/client/app/(auth)/(members)/members/page.tsx new file mode 100644 index 00000000..dc6e7a6f --- /dev/null +++ b/apps/client/app/(auth)/(members)/members/page.tsx @@ -0,0 +1,12 @@ +function Page(): JSX.Element { + return ( +
+

Bienvenue sur la page des membres

+ { + // todo: add content + } +
+ ); +} + +export default Page; diff --git a/apps/client/app/(withNavbar)/votes/page.tsx b/apps/client/app/(auth)/(members)/members/votes/page.tsx similarity index 89% rename from apps/client/app/(withNavbar)/votes/page.tsx rename to apps/client/app/(auth)/(members)/members/votes/page.tsx index 228b880f..71e3fbeb 100644 --- a/apps/client/app/(withNavbar)/votes/page.tsx +++ b/apps/client/app/(auth)/(members)/members/votes/page.tsx @@ -1,10 +1,12 @@ 'use client'; import type { Vote } from '@/app/lib/type/Votes'; +import { type User, checkSubscription } from '@/app/lib/user/utils'; import { getAllVotes } from '@/app/lib/votes/utils'; import { Badge } from '@repo/ui/components/ui/badge'; import { Button } from '@repo/ui/components/ui/button'; import { Card } from '@repo/ui/components/ui/card'; import { Loader2 } from 'lucide-react'; +import { useRouter } from 'next/navigation'; import { useEffect, useState } from 'react'; const Icons = { @@ -15,12 +17,21 @@ export default function ListVotes() { const [votes, setVotes] = useState([]); const [loading, setLoading] = useState(true); const [filter, setFilter] = useState<'all' | 'ongoing' | 'finished' | 'not_started'>('all'); + const [subscriptionChecked, setSubscriptionChecked] = useState(false); + const router = useRouter(); useEffect(() => { async function fetchData() { + if (!subscriptionChecked) { + const user = JSON.parse(localStorage.getItem('user') as string) as User; + if (!checkSubscription(user)) { + return router.push('/'); + } + setSubscriptionChecked(true); + } try { const result = await getAllVotes(); - setVotes(result); + setVotes(result.data); setLoading(false); } catch (error) { setLoading(false); @@ -28,7 +39,7 @@ export default function ListVotes() { } fetchData(); - }, []); + }, [subscriptionChecked, router]); const filteredVotes = () => { switch (filter) { diff --git a/apps/client/app/lib/user/utils.ts b/apps/client/app/lib/user/utils.ts index 288e0e2c..acf288c9 100644 --- a/apps/client/app/lib/user/utils.ts +++ b/apps/client/app/lib/user/utils.ts @@ -17,7 +17,7 @@ export async function getUserInfo(): Promise { if (!response.ok) { throw new Error('Failed to fetch user info'); } - const user = await response.json(); + const user = (await response.json()) as User; localStorage.setItem('user', JSON.stringify(user)); return user; } diff --git a/apps/client/app/lib/votes/utils.ts b/apps/client/app/lib/votes/utils.ts index 9b4a5e83..4f5ca1bd 100644 --- a/apps/client/app/lib/votes/utils.ts +++ b/apps/client/app/lib/votes/utils.ts @@ -1,6 +1,6 @@ import type { Vote } from '../type/Votes'; -export async function getAllVotes(): Promise { +export async function getAllVotes(): Promise<{ data: Vote[]; count: number }> { const API_URL = process.env.NEXT_PUBLIC_API_URL; const response = await fetch(`${API_URL}/polls?all=true`, { headers: { Authorization: `Bearer ${localStorage.getItem('access_token')}` }, diff --git a/apps/client/app/ui/NavBar.tsx b/apps/client/app/ui/NavBar.tsx index a540ac53..3482caf5 100644 --- a/apps/client/app/ui/NavBar.tsx +++ b/apps/client/app/ui/NavBar.tsx @@ -6,7 +6,7 @@ import Image from 'next/image'; import Link from 'next/link'; import { useEffect, useState } from 'react'; import type React from 'react'; -import { getUserAvatar } from '../lib/user/utils'; +import { type User, checkSubscription, getUserAvatar } from '../lib/user/utils'; interface LinkProp { name: string; @@ -38,10 +38,14 @@ function LogoutUser() { export const NavBar: React.FC = ({ links }) => { const [isAuthenticated, setIsAuthenticated] = useState(false); + const [user, setUser] = useState(); useEffect(() => { - const user = localStorage.getItem('user'); - setIsAuthenticated(user !== null); + const user = localStorage.getItem('user') as unknown as User; + setUser(user); + if (user) { + setIsAuthenticated(true); + } }, []); const navBarElements = links.map((link) => { @@ -80,6 +84,11 @@ export const NavBar: React.FC = ({ links }) => { {getUserAvatar()} + {user !== undefined && checkSubscription(user) && ( + + )}