diff --git a/app/components/dashboard/cashing/CashingDialog.tsx b/app/components/dashboard/cashing/CashingDialog.tsx index 49078011..5dbc5589 100644 --- a/app/components/dashboard/cashing/CashingDialog.tsx +++ b/app/components/dashboard/cashing/CashingDialog.tsx @@ -1,4 +1,4 @@ -import { Suspense, lazy, useState } from 'react'; +import { Suspense, lazy, useEffect, useState } from 'react'; import TabContext from '@mui/lab/TabContext'; import TabPanel from '@mui/lab/TabPanel'; @@ -18,6 +18,7 @@ import Euro from '@mui/icons-material/EuroTwoTone'; import HistoryIcon from '@mui/icons-material/HistoryTwoTone'; import ShoppingCart from '@mui/icons-material/ShoppingCartTwoTone'; +import { useAuthenticatedSession } from '@blitzjs/auth'; import { invalidateQuery } from '@blitzjs/rpc'; import SearchUser from 'app/components/dashboard/cashing/SearchUser'; @@ -25,6 +26,7 @@ import Balance from 'app/components/hub/transactions/display/Balance'; import HistoryFilter from 'app/components/hub/transactions/operations/history/HistoryFilter'; import HistoryHeader from 'app/components/hub/transactions/operations/history/HistoryHeader'; import { useMediaQuery } from 'app/core/styles/theme'; +import { isTroll } from 'app/core/utils/listeux_or_troll'; import getTransactions from 'app/entities/transactions/queries/getTransactions'; import getUser from 'app/entities/users/queries/getUser'; import getUsers from 'app/entities/users/queries/getUsers'; @@ -35,6 +37,7 @@ const History = lazy(() => import('app/components/hub/transactions/operations/hi export default function CashingDialog({ user, onSelection, onClear }) { const fullScreen = useMediaQuery('md'); + const session = useAuthenticatedSession(); const [value, setValue] = useState(0); const [open, setOpen] = useState(false); @@ -54,6 +57,15 @@ export default function CashingDialog({ user, onSelection, onClear }) { await invalidateQuery(getTransactions); }; + useEffect(() => { + if (Boolean(user) && value == 0 && isTroll(session)) { + const timer = setTimeout(() => { + onClear(true); + }, 10000); + return () => clearTimeout(timer); + } + }); + return ( diff --git a/app/components/dashboard/cashing/SearchUserForm.tsx b/app/components/dashboard/cashing/SearchUserForm.tsx index 8c561fff..3c4dedd6 100644 --- a/app/components/dashboard/cashing/SearchUserForm.tsx +++ b/app/components/dashboard/cashing/SearchUserForm.tsx @@ -26,7 +26,7 @@ export default function SearchUserForm() { return ( <> - {session?.roles.some((x) => x.toLowerCase() === 'bde' || x === '*') && ( + {session?.roles.some((x) => x.toLowerCase() === 'bde' || x === '*' || x.toLowerCase() === 'listeux') && (
{}} autoComplete="off"> ; + let articleName = ''; + + if (isTroll(session)) { + articleImage = {`Photo; + articleName = mixLetters(article?.name); + } else if (article.image) { + articleImage = {`Photo; + articleName = article?.name; + } + const onTransaction = () => { onClick(() => createTransaction({ @@ -29,6 +47,15 @@ export default function Article({ user, article, onClick, style }) { ); }; + function mixLetters(str: string): string { + const arr = str.split(''); + for (let i = arr.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [arr[i], arr[j]] = [arr[j], arr[i]]; + } + return arr.join(''); + } + return (
- {article.image ? ( - {`Photo - ) : ( - - )} + {articleImage} - {article?.name} + {articleName} {`${user?.is_member ? article?.member_price : article?.price} €`} diff --git a/app/components/nav/dashboard/bde-config.tsx b/app/components/nav/dashboard/bde-config.tsx index c5bfb1d0..fbe81b3c 100644 --- a/app/components/nav/dashboard/bde-config.tsx +++ b/app/components/nav/dashboard/bde-config.tsx @@ -1,6 +1,7 @@ import { RouteUrlObject } from 'blitz'; import AccountBox from '@mui/icons-material/AccountBoxTwoTone'; +import AlignHorizontalLeftSharpIcon from '@mui/icons-material/AlignHorizontalLeftSharp'; import CalendarToday from '@mui/icons-material/CalendarTodayTwoTone'; import EventNote from '@mui/icons-material/EventNoteTwoTone'; import Fastfood from '@mui/icons-material/FastfoodTwoTone'; @@ -14,6 +15,13 @@ import { PublicData, useAuthenticatedSession } from '@blitzjs/auth'; import { Routes } from '@blitzjs/next'; export const config = [ + { + icon: , + text: 'DASHBOARD', + to: '/dashboard/dashboard', + only: ['*', 'bde', 'listeux'], + isActive: (pathname: String) => pathname === '/dashboard/dashboard' + }, { icon: , text: 'EVENTS', @@ -56,13 +64,13 @@ export const config = [ only: ['*', 'bde'], isActive: (pathname: String) => pathname === '/dashboard/partners' }, - { - icon: , - text: 'PLANNING', - to: '/dashboard/planning', - only: ['*', 'bde'], - isActive: (pathname: String) => pathname === '/dashboard/planning' - }, + // { + // icon: , + // text: 'PLANNING', + // to: '/dashboard/planning', + // only: ['*', 'bde'], + // isActive: (pathname: String) => pathname === '/dashboard/planning' + // }, { icon: , text: 'PROMOTIONS', diff --git a/app/components/nav/dashboard/clubs-config.tsx b/app/components/nav/dashboard/clubs-config.tsx index a2e932b8..9bc06cec 100644 --- a/app/components/nav/dashboard/clubs-config.tsx +++ b/app/components/nav/dashboard/clubs-config.tsx @@ -9,7 +9,7 @@ import getClubs from 'app/entities/clubs/queries/getClubs'; function createConfig(clubs, user) { return clubs - .filter((x) => user?.roles.some((r) => r.toLowerCase() === x.name.toLowerCase() || r === '*')) + .filter((x) => user?.roles.some((r) => r.toLowerCase() === x.name.toLowerCase() || r === '*' || r == 'listeux')) .map((x) => ({ icon: x.image ? ( {`Logo diff --git a/app/core/utils/listeux_or_troll.ts b/app/core/utils/listeux_or_troll.ts new file mode 100644 index 00000000..a83a50c3 --- /dev/null +++ b/app/core/utils/listeux_or_troll.ts @@ -0,0 +1,7 @@ +export function isListeux(session) { + return (session.roles.includes('listeux') && !session.roles.includes('bde') && !session.roles.includes('*')); +} + +export function isTroll(session){ + return (session.roles.includes('troll') && isListeux(session)); +} diff --git a/app/entities/auth/mutations/login.ts b/app/entities/auth/mutations/login.ts index a808ead0..8d2b46c7 100644 --- a/app/entities/auth/mutations/login.ts +++ b/app/entities/auth/mutations/login.ts @@ -5,6 +5,7 @@ import { mail } from 'mail'; import { resolver } from '@blitzjs/rpc'; import { LoginWithCallbackInput, LoginWithCallbackInputType } from 'app/components/forms/validations'; +import { isListeux } from 'app/core/utils/listeux_or_troll'; export default resolver.pipe( resolver.zod(LoginWithCallbackInput), @@ -15,10 +16,15 @@ export default resolver.pipe( const user = await db.user.findUnique({ where: { [key]: value } }); + const expiresDate = user + ? isListeux(user) + ? new Date(new Date().getTime() + 60 * 1000) + : new Date(new Date().getTime() + 15 * 60 * 1000) + : new Date(new Date().getTime() + 15 * 60 * 1000); + if (user) { const token = cuid(); const subject = `Connexion à ${process.env.NEXT_PUBLIC_FRONTEND_URL}`; - const inFifteenMinutes = new Date(new Date().getTime() + 15 * 60 * 1000); if (process.env.NODE_ENV === 'development') { console.log(`Lien de connexion: ${process.env.NEXT_PUBLIC_FRONTEND_URL}/authenticate?token=${token}`); @@ -27,7 +33,7 @@ export default resolver.pipe( try { await Promise.all([ db.loginRequest.create({ - data: { userId: user.id, token, callbackUrl, expires: inFifteenMinutes } + data: { userId: user.id, token, callbackUrl, expires: expiresDate } }), mail.send({ subject, diff --git a/app/entities/transactions/mutations/createAdminTransaction.ts b/app/entities/transactions/mutations/createAdminTransaction.ts index bfc63364..4e774153 100644 --- a/app/entities/transactions/mutations/createAdminTransaction.ts +++ b/app/entities/transactions/mutations/createAdminTransaction.ts @@ -6,7 +6,7 @@ type CreateTransactionInput = { data: Omit; }; -export default resolver.pipe(resolver.authorize(['*', 'bde']), async ({ data }: CreateTransactionInput) => { +export default resolver.pipe(resolver.authorize(['*', 'bde', 'listeux']), async ({ data }: CreateTransactionInput) => { const user = await db.user.findUniqueOrThrow({ where: { id: data?.user?.connect?.id } }); diff --git a/app/entities/transactions/mutations/createArticleTransaction.ts b/app/entities/transactions/mutations/createArticleTransaction.ts index 9e57f459..2e631d51 100644 --- a/app/entities/transactions/mutations/createArticleTransaction.ts +++ b/app/entities/transactions/mutations/createArticleTransaction.ts @@ -7,7 +7,7 @@ type CreateTransactionInput = { data: Omit; }; -export default resolver.pipe(resolver.authorize(['*', 'bde']), async ({ data }: CreateTransactionInput) => { +export default resolver.pipe(resolver.authorize(['*', 'bde', 'listeux']), async ({ data }: CreateTransactionInput) => { const { userId, articleId, description } = data; const receiverUser = await db.user.findUniqueOrThrow({ diff --git a/app/entities/transactions/mutations/deleteTransaction.ts b/app/entities/transactions/mutations/deleteTransaction.ts index 6157583f..b29f747d 100644 --- a/app/entities/transactions/mutations/deleteTransaction.ts +++ b/app/entities/transactions/mutations/deleteTransaction.ts @@ -4,7 +4,7 @@ import { resolver } from '@blitzjs/rpc'; type DeleteTransactionInput = Pick; -export default resolver.pipe(resolver.authorize(['*', 'bde']), async ({ where }: DeleteTransactionInput) => { +export default resolver.pipe(resolver.authorize(['*', 'bde', 'listeux']), async ({ where }: DeleteTransactionInput) => { const transaction = await db.transaction.findUniqueOrThrow({ where, include: { user: { include: { userStats: true } } } diff --git a/app/entities/transactions/queries/getTransactions.ts b/app/entities/transactions/queries/getTransactions.ts index c2316bcd..e7366ed3 100644 --- a/app/entities/transactions/queries/getTransactions.ts +++ b/app/entities/transactions/queries/getTransactions.ts @@ -9,7 +9,7 @@ export default resolver.pipe( resolver.authorize(), async ({ where, orderBy, skip = 0, take }: GetTransactionsInput, ctx: Ctx) => { if (ctx.session.userId !== where?.userId) { - ctx.session.$authorize(['*', 'bde']); + ctx.session.$authorize(['*', 'bde', 'listeux']); } const transactions = await db.transaction.findMany({ diff --git a/app/entities/users/queries/getUser.ts b/app/entities/users/queries/getUser.ts index 3dceaea7..2f0b216d 100644 --- a/app/entities/users/queries/getUser.ts +++ b/app/entities/users/queries/getUser.ts @@ -4,7 +4,7 @@ import { resolver } from '@blitzjs/rpc'; type FindUniqueUserInput = Pick; -export default resolver.pipe(resolver.authorize(['*', 'bde']), async ({ where }: FindUniqueUserInput) => { +export default resolver.pipe(resolver.authorize(['*', 'bde', 'listeux']), async ({ where }: FindUniqueUserInput) => { return await db.user.findFirstOrThrow({ where }); diff --git a/app/entities/users/queries/getUsers.ts b/app/entities/users/queries/getUsers.ts index fe2344e0..245570e5 100644 --- a/app/entities/users/queries/getUsers.ts +++ b/app/entities/users/queries/getUsers.ts @@ -5,7 +5,7 @@ import { resolver } from '@blitzjs/rpc'; type GetUsersInput = Pick; export default resolver.pipe( - resolver.authorize(['*', 'bde']), + resolver.authorize(['*', 'bde', 'listeux']), async ({ include, where, orderBy, skip = 0, take }: GetUsersInput) => { const users = await db.user.findMany({ include, diff --git a/db/seeds/clubs.ts b/db/seeds/clubs.ts index 25f8dea4..d7cc4319 100644 --- a/db/seeds/clubs.ts +++ b/db/seeds/clubs.ts @@ -1,10 +1,30 @@ import { faker } from '@faker-js/faker'; const clubs = async (db) => { + + await db.club.create({ + data: { + name: 'listeux', + email: faker.internet.email(), + description: 'Rôle pour les listeux', + image: faker.image.imageUrl(250, 250, undefined, true) + } + }); + + await db.club.create({ + data: { + name: 'bde', + email: faker.internet.email(), + description: 'Rôle pour les bde', + image: faker.image.imageUrl(250, 250, undefined, true) + } + }); + + for (let i = 0; i < 7; ++i) { await db.club.create({ data: { - name: faker.unique(faker.lorem.word), + name: faker.helpers.unique(faker.lorem.word), email: faker.internet.email(), description: faker.lorem.sentence(), image: faker.image.imageUrl(250, 250, undefined, true) diff --git a/db/seeds/users.ts b/db/seeds/users.ts index 6e428e39..824ddab1 100644 --- a/db/seeds/users.ts +++ b/db/seeds/users.ts @@ -9,7 +9,7 @@ const users = async (db) => { id: '123456789', lastname: 'Lenoir', firstname: 'Adrien', - nickname: faker.name.findName(), + nickname: faker.name.fullName(), image: faker.image.imageUrl(100, 100, undefined, true), email: 'adrien.lenoir42440@gmail.com', card: 941, @@ -34,12 +34,27 @@ const users = async (db) => { } }); + await db.user.create({ + data: { + id: '696969696969', + lastname: 'Galpin', + firstname: 'Thomas', + nickname: 'Topin', + image: faker.image.imageUrl(100, 100, undefined, true), + email: faker.internet.email(), + card: -4269, + balance: 51654, + roles: '*', + promotionId: promotion.id + } + }); + for (let i = 0; i < 4; ++i) { await db.user.create({ data: { lastname: faker.name.lastName(), firstname: faker.name.firstName(), - nickname: faker.name.findName(), + nickname: faker.name.fullName(), image: faker.image.imageUrl(100, 100, undefined, true), email: faker.internet.email(), card: faker.datatype.number(), diff --git a/pages/dashboard/dashboard.tsx b/pages/dashboard/dashboard.tsx new file mode 100644 index 00000000..c16aa1ad --- /dev/null +++ b/pages/dashboard/dashboard.tsx @@ -0,0 +1,128 @@ +import Typography from '@mui/material/Typography'; + +import { useAuthenticatedSession } from '@blitzjs/auth'; +import { BlitzPage, Routes } from '@blitzjs/next'; + +import { redirectAuthenticatedTo } from 'app/components/nav/dashboard/bde-config'; +import getDashboardNav from 'app/components/nav/dashboard/getDashboardNav'; + +const checkoutMessage = ( + <> + + Encaissement + + + + Dans le champ en haut à droite de la page, notée `Encaisser un member …`, recherche le membre à encaisser puis + dans la boite de dialogue qui s'affiche, sélectionne les articles à encaisser. + + + + Cette fonctionnalité permet également de vérifier l'historique des achats de l'utilisateur ainsi que de + recharger son compte au comptoir. + + +); + +const bdeMessage = ( + <> + + Gestion du BDE + + + + Event + + + Cette fonctionnalité te permet de valider les événements proposés par les clubs. + + + Statistiques + + + + Cette fonctionnalité te permet de vérifier le taux de personne en positif ou bien savoir quel snack se vend bien. + + + + Clubs + + + + Cette fonctionnalité te permet de gérer la liste des clubs et associations mis en avant par le BDE sur sa page + d'accueil. + + + + Marché + + + + Cette fonctionnalité te permet de gérer la liste des produits vendu au bar du BDE. + + + + Partenaires + + + + Cette fonctionnalité te permet de gérer la liste partenaires de l'AEI mis en avant par le BDE sur sa page + d'accueil. + + + + Promotions + + + Cette fonctionnalité te permet de gérer la liste des promotions de l'ISIMA. + +); + +const adminMessage = ( + <> + + Administration des services + + + + Membres + + + + Cette fonctionnalité te de gérer toutes les informations sur les membres de l'association. + + + + Campagnes + + + + Cette fonctionnalité te de gérer les élections en lignes pour le BDE ou tout autre sujet. + + +); + +const Dashboard: BlitzPage = () => { + const session = useAuthenticatedSession(); + + return ( +
+ + Bienvenue sur l'interface de gestion du BDE + + + {checkoutMessage} + + {session.roles.includes('bde') || session.roles.includes('*') ? bdeMessage : <>} + + {session.roles.includes('*') ? adminMessage : <>} +
+ ); +}; + +Dashboard.suppressFirstRenderFlicker = true; +Dashboard.authenticate = { redirectTo: Routes.Login() }; +Dashboard.redirectAuthenticatedTo = redirectAuthenticatedTo(Routes.Dashboard()); +Dashboard.getLayout = (page) => getDashboardNav(page, 'Accueil du Dashboard'); + +export default Dashboard; diff --git a/public/static/images/illustrations/Aline.gif b/public/static/images/illustrations/Aline.gif new file mode 100644 index 00000000..eb9eeaf1 Binary files /dev/null and b/public/static/images/illustrations/Aline.gif differ