Skip to content

Commit

Permalink
Implement Listeux functionality (#51)
Browse files Browse the repository at this point in the history
* add new dashboard page for listeux

* Reduce token availability for listeux

* add troll aline image for listeux

* allow listeux to undo a sell

* added auto windows close when taking too long to cash

* make the article image a GIF for listeux

---------

Co-authored-by: Taha Belkhiri <belkhiri.taha53@gmail.com>
Co-authored-by: Venceslas Duet <duet.venceslas@orange.fr>
Co-authored-by: Adrien Lenoir <adrien.lenoir42440@gmail.com>
  • Loading branch information
4 people authored Nov 23, 2023
1 parent 234a622 commit a4024cf
Show file tree
Hide file tree
Showing 17 changed files with 246 additions and 27 deletions.
14 changes: 13 additions & 1 deletion app/components/dashboard/cashing/CashingDialog.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -18,13 +18,15 @@ 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';
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';
Expand All @@ -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);
Expand All @@ -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 (
<NoSsr>
<TabContext value={value.toString()}>
Expand Down
2 changes: 1 addition & 1 deletion app/components/dashboard/cashing/SearchUserForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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') && (
<div className="w-full md:w-80 p-4 mb-4">
<Form onSubmit={() => {}} autoComplete="off">
<SearchUser
Expand Down
35 changes: 29 additions & 6 deletions app/components/dashboard/cashing/catalog/Article.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,37 @@ import Typography from '@mui/material/Typography';

import Image from 'next/image';

import { useAuthenticatedSession } from '@blitzjs/auth';
import { useMutation } from '@blitzjs/rpc';

import { useMediaQuery } from 'app/core/styles/theme';
import createArticleTransaction from 'app/entities/transactions/mutations/createArticleTransaction';

import Aline from 'public/static/images/illustrations/Aline.gif';

import { isTroll } from 'app/core/utils/listeux_or_troll';

const GUTTER_SIZE = 16;

export default function Article({ user, article, onClick, style }) {
const fullScreen = useMediaQuery('md');
const session = useAuthenticatedSession();

const size = fullScreen ? 40 : 50;

const [createTransaction] = useMutation(createArticleTransaction);

let articleImage = <Skeleton variant="rectangular" width={size} height={size} animation={false} />;
let articleName = '';

if (isTroll(session)) {
articleImage = <Image src={Aline} width={size} height={size} alt={`Photo ${article?.name}`} />;
articleName = mixLetters(article?.name);
} else if (article.image) {
articleImage = <Image src={article.image} width={size} height={size} alt={`Photo ${article?.name}`} />;
articleName = article?.name;
}

const onTransaction = () => {
onClick(() =>
createTransaction({
Expand All @@ -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 (
<div
className="overflow-hidden"
Expand All @@ -41,13 +68,9 @@ export default function Article({ user, article, onClick, style }) {
}}
>
<ButtonBase className="flex flex-col w-full h-full" onClick={onTransaction}>
{article.image ? (
<Image src={article.image} width={size} height={size} alt={`Photo ${article?.name}`} />
) : (
<Skeleton variant="rectangular" width={size} height={size} animation={false} />
)}
{articleImage}
<Typography variant="caption" color="inherit" noWrap>
{article?.name}
{articleName}
</Typography>
<Typography variant="caption" color="inherit" noWrap>
{`${user?.is_member ? article?.member_price : article?.price} €`}
Expand Down
22 changes: 15 additions & 7 deletions app/components/nav/dashboard/bde-config.tsx
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -14,6 +15,13 @@ import { PublicData, useAuthenticatedSession } from '@blitzjs/auth';
import { Routes } from '@blitzjs/next';

export const config = [
{
icon: <AlignHorizontalLeftSharpIcon />,
text: 'DASHBOARD',
to: '/dashboard/dashboard',
only: ['*', 'bde', 'listeux'],
isActive: (pathname: String) => pathname === '/dashboard/dashboard'
},
{
icon: <EventNote />,
text: 'EVENTS',
Expand Down Expand Up @@ -56,13 +64,13 @@ export const config = [
only: ['*', 'bde'],
isActive: (pathname: String) => pathname === '/dashboard/partners'
},
{
icon: <CalendarToday />,
text: 'PLANNING',
to: '/dashboard/planning',
only: ['*', 'bde'],
isActive: (pathname: String) => pathname === '/dashboard/planning'
},
// {
// icon: <CalendarToday />,
// text: 'PLANNING',
// to: '/dashboard/planning',
// only: ['*', 'bde'],
// isActive: (pathname: String) => pathname === '/dashboard/planning'
// },
{
icon: <School />,
text: 'PROMOTIONS',
Expand Down
2 changes: 1 addition & 1 deletion app/components/nav/dashboard/clubs-config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 ? (
<Image src={x.image} width={40} height={40} alt={`Logo ${x.name}`} />
Expand Down
7 changes: 7 additions & 0 deletions app/core/utils/listeux_or_troll.ts
Original file line number Diff line number Diff line change
@@ -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));
}
10 changes: 8 additions & 2 deletions app/entities/auth/mutations/login.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -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}`);
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ type CreateTransactionInput = {
data: Omit<Prisma.TransactionCreateInput, 'type' | 'prevBalance'>;
};

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 }
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ type CreateTransactionInput = {
data: Omit<Prisma.TransactionUncheckedCreateInput, 'type' | 'amount' | 'prevBalance'>;
};

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({
Expand Down
2 changes: 1 addition & 1 deletion app/entities/transactions/mutations/deleteTransaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { resolver } from '@blitzjs/rpc';

type DeleteTransactionInput = Pick<Prisma.TransactionDeleteArgs, 'where'>;

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 } } }
Expand Down
2 changes: 1 addition & 1 deletion app/entities/transactions/queries/getTransactions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down
2 changes: 1 addition & 1 deletion app/entities/users/queries/getUser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { resolver } from '@blitzjs/rpc';

type FindUniqueUserInput = Pick<Prisma.UserFindUniqueArgs, 'where'>;

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
});
Expand Down
2 changes: 1 addition & 1 deletion app/entities/users/queries/getUsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { resolver } from '@blitzjs/rpc';
type GetUsersInput = Pick<Prisma.UserFindManyArgs, 'include' | 'where' | 'orderBy' | 'skip' | 'take'>;

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,
Expand Down
22 changes: 21 additions & 1 deletion db/seeds/clubs.ts
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
19 changes: 17 additions & 2 deletions db/seeds/users.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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(),
Expand Down
Loading

0 comments on commit a4024cf

Please sign in to comment.