Skip to content

Commit

Permalink
Merge pull request #8 from Varkoff/05-build-that-app
Browse files Browse the repository at this point in the history
Build That App
  • Loading branch information
Varkoff authored Jun 2, 2024
2 parents 0d4ee2f + cb0d4ca commit 74f23ef
Show file tree
Hide file tree
Showing 37 changed files with 2,312 additions and 115 deletions.
4 changes: 4 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"tabWidth": 2,
"useTabs": false
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ Retrouvez le guide vidéo pour configurer ce projet sur YouTube (en français)
- [Partie 3: Intégration Design System | Figma, Tailwind CSS & Shadcn UI](https://www.youtube.com/watch?v=GWfZewdFx4o&list=PL2TfCPpDwZVTQr3Ox9KT0Ex2D-QajUyhM&index=3)
- [Partie 4: Authentification avec Redis, express-session, Passport.js](https://youtu.be/SyuXRIbECEY?list=PL2TfCPpDwZVTQr3Ox9KT0Ex2D-QajUyhM)
- [Partie 5: Authentification par token, inscription avec Redis, express-session, Passport.js](https://youtu.be/k6KrmuVgvec)
- [Partie 6: Développement des fonctionnalités principales d'échange de service, faire une offre, éditer le profil ...](https://youtu.be/0C4Xh1x7flY)

### Motivation

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
-- CreateTable
CREATE TABLE "Offer" (
"id" TEXT NOT NULL,
"title" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"description" TEXT NOT NULL,
"price" DOUBLE PRECISION NOT NULL,
"active" BOOLEAN NOT NULL DEFAULT false,
"recurring" BOOLEAN NOT NULL DEFAULT false,
"userId" TEXT NOT NULL,

CONSTRAINT "Offer_pkey" PRIMARY KEY ("id")
);

-- CreateTable
CREATE TABLE "Transaction" (
"id" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"offerId" TEXT NOT NULL,
"userId" TEXT NOT NULL,

CONSTRAINT "Transaction_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "Offer" ADD CONSTRAINT "Offer_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Transaction" ADD CONSTRAINT "Transaction_offerId_fkey" FOREIGN KEY ("offerId") REFERENCES "Offer"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Transaction" ADD CONSTRAINT "Transaction_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/*
Warnings:
- A unique constraint covering the columns `[offerId,userId]` on the table `Transaction` will be added. If there are existing duplicate values, this will fail.
*/
-- CreateIndex
CREATE UNIQUE INDEX "Transaction_offerId_userId_key" ON "Transaction"("offerId", "userId");
17 changes: 17 additions & 0 deletions backend/prisma/migrations/20240528171404_messages/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-- CreateTable
CREATE TABLE "Message" (
"id" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedAt" TIMESTAMP(3) NOT NULL,
"content" TEXT NOT NULL,
"userId" TEXT NOT NULL,
"transactionId" TEXT NOT NULL,

CONSTRAINT "Message_pkey" PRIMARY KEY ("id")
);

-- AddForeignKey
ALTER TABLE "Message" ADD CONSTRAINT "Message_userId_fkey" FOREIGN KEY ("userId") REFERENCES "User"("id") ON DELETE RESTRICT ON UPDATE CASCADE;

-- AddForeignKey
ALTER TABLE "Message" ADD CONSTRAINT "Message_transactionId_fkey" FOREIGN KEY ("transactionId") REFERENCES "Transaction"("id") ON DELETE RESTRICT ON UPDATE CASCADE;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
-- AlterTable
ALTER TABLE "Message" ADD COLUMN "price" DOUBLE PRECISION,
ADD COLUMN "status" INTEGER DEFAULT 0;
59 changes: 53 additions & 6 deletions backend/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,68 @@ datasource db {
}

model User {
id String @id @default(cuid())
id String @id @default(cuid())
email String @unique
name String?
password String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
sessions Session[]
sessions Session[]
offers Offer[]
transactions Transaction[]
Message Message[]
}

model Session {
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id])
id String @id @default(cuid())
userId String
user User @relation(fields: [userId], references: [id])
ipAddress String?
userAgent String?
sessionToken String @unique
sessionToken String @unique
}

model Offer {
id String @id @default(cuid())
title String
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
description String
price Float
active Boolean @default(false) // Est-ce que l'offre est visible sur le site ?
recurring Boolean @default(false) // Exemple : Si l'utilisateur vend un objet,
// il ne peut vendre cet objet qu'une seule fois.
// Par conre, s'il rend un service, il peut le rendre plusieurs fois. Dans ce cas, l'application ne va pas supprimer l'offre après la première vente.
userId String
user User @relation(fields: [userId], references: [id])
transactions Transaction[]
}

model Transaction {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
offerId String
offer Offer @relation(fields: [offerId], references: [id])
userId String
user User @relation(fields: [userId], references: [id])
messages Message[]
@@unique([offerId, userId])
}

model Message {
id String @id @default(cuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
content String
userId String
user User @relation(fields: [userId], references: [id])
transactionId String
transaction Transaction @relation(fields: [transactionId], references: [id])
price Float?
status Int? @default(0) // 0 = message, 10 = offre en attente, 20 = offre acceptée, 90 = offre refusée
}
9 changes: 7 additions & 2 deletions backend/src/auth/auth.controller.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Controller, Get, Next, Post, Redirect, Req, Res, UseGuards } from '@nestjs/common';
import { Controller, Get, Next, Post, Query, Redirect, Req, Res, UseGuards } from '@nestjs/common';
import { NextFunction, Response } from 'express';
import { LocalAuthGuard } from './local-auth.guard';

Expand All @@ -7,7 +7,12 @@ export class AuthController {
@UseGuards(LocalAuthGuard)
@Get('/authenticate')
@Redirect('/')
login() {
login(
@Query('redirectTo') redirectTo: string,
) {
return {
url: redirectTo
}
}

@Post('auth/logout')
Expand Down
2 changes: 1 addition & 1 deletion backend/src/auth/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export class AuthService {
}
}
return {
message: "L'utilisateur existe.",
message: "Cet email est déjà utilisé.",
error: false,
};
};
Expand Down
2 changes: 1 addition & 1 deletion backend/src/auth/local-auth.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export class LocalAuthGuard extends AuthGuard('local') {

// @ts-expect-error Fix that later
handleRequest(err, user, info) {
console.log({ user, err, info })
// console.log({ user, err, info })
// You can throw an exception based on either "info" or "err" arguments
if (err || !user) {
throw err || new UnauthorizedException("Vous n'avez pas le droit d'accéder à cette page.");
Expand Down
64 changes: 64 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
{
"$schema": "https://biomejs.dev/schemas/1.7.1/schema.json",
"organizeImports": {
"enabled": true
},
"files": {
"ignore": ["**/*.json"]
},

"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 2
},
"javascript": {
"parser": {
"unsafeParameterDecoratorsEnabled": true
}
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"correctness": {
"noUnusedImports": "error",
"noUnusedVariables": "error",
"useExhaustiveDependencies": "off",
"noUnsafeOptionalChaining": "off"
},
"style": {
"noUnusedTemplateLiteral": "off",
"useTemplate": "off",
"useSelfClosingElements": "off",
"noParameterAssign": "off",
"noUselessElse": "off",
"useImportType": "off"
},
"security": {
"noDangerouslySetInnerHtml": "off"
},
"a11y": {
"useButtonType": "off",
"noSvgWithoutTitle": "off",
"noAutofocus": "off"
},
"complexity": {
"noUselessFragments": "off",
"useLiteralKeys": "off",
"noForEach": "off",
"useOptionalChain": "off"
},
"suspicious": {
"noArrayIndexKey": "off",
"noExplicitAny": "off",
"noMisleadingCharacterClass": "off",
"noAssignInExpressions": "off",
"noShadowRestrictedNames": "off",
"noGlobalIsNan": "off",
"useDefaultSwitchClauseLast": "off"
}
}
}
}

Binary file modified cache/dump.rdb
Binary file not shown.
2 changes: 1 addition & 1 deletion frontend/app/components/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const Footer = () => {
return (<footer className='overflow-x-auto px-3 py-2 flex items-center justify-between gap-4 mt-auto bg-lightTurquoise'>
<FooterLinkItem href='/' icon={<Search />} label='Rechercher' />
<FooterLinkItem href='/' icon={<Users />} label='Offreurs' />
<FooterLinkItem href='/home' icon={<Plus />} label='Demandes' />
<FooterLinkItem href='/' icon={<Plus />} label='Demandes' />
<FooterLinkItem href='/' icon={<Star />} label='Favoris' />
<FooterLinkItem href='/' icon={<Mail />} label='Message' />
</footer>)
Expand Down
15 changes: 9 additions & 6 deletions frontend/app/components/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,24 @@ export const Navbar = ({ logo }: { logo: string }) => {
<Link to='/'>
<img src={logo} className='w-full h-auto max-w-[120px]' />
</Link>
<div className='flex gap-2'>
<div className='flex gap-2 items-center'>
{user ? (
<>
<span>{user.name}</span>
<Link to='/'>
<span className='text-xs'>{user.name}</span>
<Link className='text-xs' to='/transactions'>
Demandes
</Link>
<Link className='text-xs' to='/my-services'>
<ReceiptEuro className='flex-shrink-0' />
</Link>
<Link to='/'>
<Link className='text-xs' to='/'>
<Bell className='fill-white flex-shrink-0' />
</Link>
<Link to='/profile'>
<Link className='text-xs' to='/profile'>
<UserRound className='flex-shrink-0' />
</Link>
<form method='POST' action='/auth/logout'>
<button type='submit'>Se déconnecter</button>
<button type='submit' className='text-xs'>Se déconnecter</button>
</form>
</>
) : (
Expand Down
Loading

0 comments on commit 74f23ef

Please sign in to comment.