diff --git a/.kontinuous/env/dev/values.yaml b/.kontinuous/env/dev/values.yaml
index da2c5705..ecdf5f42 100644
--- a/.kontinuous/env/dev/values.yaml
+++ b/.kontinuous/env/dev/values.yaml
@@ -16,7 +16,7 @@ jobs:
checkout: false
shell: sh
image: "{{ .Values.global.registry }}{{ if .Values.global.imageProject }}{{ print `/` .Values.global.imageProject }}{{ end }}/{{ .Values.global.imageRepository }}/app:{{ .Values.global.imageTag }}"
- run: "yarn seed"
+ run: "yarn payload migrate && yarn seed:prod"
envFrom:
- secretRef:
name: pg-app
diff --git a/README.md b/README.md
index 74b17bf0..0e17c7fa 100644
--- a/README.md
+++ b/README.md
@@ -4,6 +4,14 @@
## Developpement
+## Base de donnée
+
+Lancez la base de donnée Postgres via docker compose :
+
+```bash
+docker compose up -d
+```
+
### Webapp
Accédez au dossier de l'application NextJS webapp :
@@ -27,7 +35,7 @@ yarn
Générez les données de test :
```bash
-yarn seed
+yarn seed:dev
```
Lancez l'application, qui sera accessible sur le port 3000 :
@@ -35,3 +43,9 @@ Lancez l'application, qui sera accessible sur le port 3000 :
```bash
yarn dev
```
+
+Voici les informations des utilisateurs prêts à être utilisés en développement grâce aux données de test :
+| Email | Type de compte | Mot de passe |
+| -------- | -------- | -------- |
+| user@test.loc | Utilisateur | user123 |
+| admin@test.loc | Administrateur | admin123 |
diff --git a/imports/coupons.csv b/imports/coupons.csv
new file mode 100644
index 00000000..40752c11
--- /dev/null
+++ b/imports/coupons.csv
@@ -0,0 +1,23 @@
+code,validityTo
+H1D1,01/06/24
+H1D2,02/06/24
+H1D3,03/06/24
+H1D4,04/06/24
+H1D5,05/06/24
+H1D6,06/06/24
+H1D7,07/06/24
+H1D8,08/06/24
+H1D9,09/06/24
+H1D10,10/06/24
+H1D11,11/06/24
+H1D12,12/06/24
+H1D13,13/06/24
+H1D14,14/06/24
+H1D15,15/06/24
+H1D16,16/06/24
+H1D17,17/06/24
+H1D18,18/06/24
+H1D19,19/06/24
+H1D20,20/06/24
+H1D21,21/06/24
+H1D22,22/06/24
diff --git a/webapp/.env.example b/webapp/.env.example
index 2686ec17..24bd01a5 100644
--- a/webapp/.env.example
+++ b/webapp/.env.example
@@ -1,4 +1,4 @@
-DATABASE_URL=postgres://user:password@localhost:5432/dbname
+DATABASE_URL=postgres://user:password@localhost:5433/carte-jeune-engage
PAYLOAD_SECRET=SOME_SECRET
PAYLOAD_CONFIG_PATH=payload/payload.config.ts
NEXT_PUBLIC_JWT_NAME=cje-jwt
diff --git a/webapp/package.json b/webapp/package.json
index fa9e8392..5d1b8371 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -6,19 +6,23 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
- "seed": "PAYLOAD_DROP_DATABASE=true tsx ./src/payload/seed/index.ts",
+ "seed:dev": "PAYLOAD_DROP_DATABASE=true tsx ./src/payload/seed/index.ts",
+ "seed:prod": "tsx ./src/payload/seed/index.ts",
+ "payload": "PAYLOAD_CONFIG_PATH=./src/payload/payload.config.ts payload",
"lint": "next lint"
},
"dependencies": {
"@aws-sdk/client-s3": "^3.490.0",
"@aws-sdk/lib-storage": "^3.490.0",
+ "@chakra-ui/icons": "^2.1.1",
"@chakra-ui/next-js": "^2.2.0",
"@chakra-ui/react": "^2.8.2",
"@ducanh2912/next-pwa": "^10.1.0",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
+ "@gsap/react": "^2.1.0",
"@payloadcms/bundler-webpack": "^1.0.5",
- "@payloadcms/db-postgres": "^0.3.0",
+ "@payloadcms/db-postgres": "^0.4.0",
"@payloadcms/next-payload": "^0.1.11",
"@payloadcms/plugin-cloud-storage": "^1.1.1",
"@payloadcms/richtext-slate": "^1.3.1",
@@ -32,9 +36,12 @@
"cookies-next": "^4.1.0",
"dotenv": "^16.3.1",
"framer-motion": "^10.16.16",
+ "gsap": "^3.12.5",
+ "ignore-styles": "^5.0.1",
"jwt-decode": "^4.0.0",
"next": "13.5.5",
- "payload": "^2.6.0",
+ "papaparse": "^5.4.1",
+ "payload": "^2.8.2",
"react": "^18",
"react-dom": "^18",
"react-hook-form": "^7.49.2",
@@ -43,11 +50,11 @@
"superjson": "^1.13.3",
"tsx": "^4.7.0",
"usehooks-ts": "^2.9.2",
- "zod": "^3.22.4",
- "ignore-styles": "^5.0.1"
+ "zod": "^3.22.4"
},
"devDependencies": {
"@types/node": "^20",
+ "@types/papaparse": "^5",
"@types/react": "^18",
"@types/react-dom": "^18",
"typescript": "^5",
diff --git a/webapp/public/images/seeds/categories/bank.png b/webapp/public/images/seeds/categories/bank.png
new file mode 100644
index 00000000..a1f2f57e
Binary files /dev/null and b/webapp/public/images/seeds/categories/bank.png differ
diff --git a/webapp/public/images/seeds/categories/care.svg b/webapp/public/images/seeds/categories/care.svg
deleted file mode 100644
index 7050734a..00000000
--- a/webapp/public/images/seeds/categories/care.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/webapp/public/images/seeds/categories/equipment.png b/webapp/public/images/seeds/categories/equipment.png
new file mode 100644
index 00000000..4a82ab56
Binary files /dev/null and b/webapp/public/images/seeds/categories/equipment.png differ
diff --git a/webapp/public/images/seeds/categories/hobby.png b/webapp/public/images/seeds/categories/hobby.png
new file mode 100644
index 00000000..4af75708
Binary files /dev/null and b/webapp/public/images/seeds/categories/hobby.png differ
diff --git a/webapp/public/images/seeds/categories/hosting.png b/webapp/public/images/seeds/categories/hosting.png
new file mode 100644
index 00000000..23b52953
Binary files /dev/null and b/webapp/public/images/seeds/categories/hosting.png differ
diff --git a/webapp/public/images/seeds/categories/hygiene.png b/webapp/public/images/seeds/categories/hygiene.png
new file mode 100644
index 00000000..016ebdfd
Binary files /dev/null and b/webapp/public/images/seeds/categories/hygiene.png differ
diff --git a/webapp/public/images/seeds/categories/mobility.png b/webapp/public/images/seeds/categories/mobility.png
index f47424b3..85a96dc5 100644
Binary files a/webapp/public/images/seeds/categories/mobility.png and b/webapp/public/images/seeds/categories/mobility.png differ
diff --git a/webapp/public/images/seeds/categories/services.svg b/webapp/public/images/seeds/categories/services.svg
deleted file mode 100644
index 861746fd..00000000
--- a/webapp/public/images/seeds/categories/services.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/webapp/public/images/seeds/categories/shop.png b/webapp/public/images/seeds/categories/shop.png
new file mode 100644
index 00000000..38660cac
Binary files /dev/null and b/webapp/public/images/seeds/categories/shop.png differ
diff --git a/webapp/public/images/seeds/categories/shop.svg b/webapp/public/images/seeds/categories/shop.svg
deleted file mode 100644
index cf569220..00000000
--- a/webapp/public/images/seeds/categories/shop.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/webapp/public/images/seeds/categories/sport.png b/webapp/public/images/seeds/categories/sport.png
new file mode 100644
index 00000000..2dbe3e74
Binary files /dev/null and b/webapp/public/images/seeds/categories/sport.png differ
diff --git a/webapp/public/images/seeds/categories/telephony.png b/webapp/public/images/seeds/categories/telephony.png
new file mode 100644
index 00000000..5fe74d66
Binary files /dev/null and b/webapp/public/images/seeds/categories/telephony.png differ
diff --git a/webapp/public/images/seeds/categories/telephony.svg b/webapp/public/images/seeds/categories/telephony.svg
deleted file mode 100644
index 42013d1e..00000000
--- a/webapp/public/images/seeds/categories/telephony.svg
+++ /dev/null
@@ -1,9 +0,0 @@
-
diff --git a/webapp/public/images/seeds/partners/cora.svg b/webapp/public/images/seeds/partners/cora.svg
new file mode 100644
index 00000000..905b8787
--- /dev/null
+++ b/webapp/public/images/seeds/partners/cora.svg
@@ -0,0 +1,9 @@
+
diff --git a/webapp/public/pwa/manifest.json b/webapp/public/pwa/manifest.json
index 93305199..80e2b31a 100644
--- a/webapp/public/pwa/manifest.json
+++ b/webapp/public/pwa/manifest.json
@@ -50,8 +50,8 @@
"purpose": "any"
}
],
- "theme_color": "#F7F7FA",
- "background_color": "#F7F7FA",
+ "theme_color": "#F7F7F7",
+ "background_color": "#F7F7F7",
"start_url": "/",
"display": "standalone",
"orientation": "portrait"
diff --git a/webapp/src/components/InstallationBanner.tsx b/webapp/src/components/InstallationBanner.tsx
index fbbd6aa3..86eabbf4 100644
--- a/webapp/src/components/InstallationBanner.tsx
+++ b/webapp/src/components/InstallationBanner.tsx
@@ -1,7 +1,8 @@
import React, { useEffect, useState } from "react";
-import { Button, Flex, Icon, Text, useToast } from "@chakra-ui/react";
+import { Box, Button, Flex, Icon, Text, useToast } from "@chakra-ui/react";
import { useAuth } from "~/providers/Auth";
import { useLocalStorage } from "usehooks-ts";
+import { CloseIcon } from "@chakra-ui/icons";
interface BeforeInstallPromptEvent extends Event {
readonly platforms: Array;
@@ -81,7 +82,7 @@ const InstallationBanner: React.FC = () => {
return null;
return (
- {
p={4}
borderRadius={8}
bgColor="primary.500"
- alignItems="center"
- justifyContent="space-between"
>
-
-
- Installer l'application
-
-
- Pour une meilleure expérience, installez l'app sur votre téléphone.
-
+
+
+
+ Installer l'application
+
+
+ Pour une meilleure expérience, installez l'app sur votre téléphone.
+
+
+
+ setUserOutcome("dismissed")}
+ />
-
-
+
);
};
diff --git a/webapp/src/components/LoadingLoader.tsx b/webapp/src/components/LoadingLoader.tsx
new file mode 100644
index 00000000..61b262fd
--- /dev/null
+++ b/webapp/src/components/LoadingLoader.tsx
@@ -0,0 +1,13 @@
+import { Spinner } from "@chakra-ui/react";
+
+export default function LoadingLoader() {
+ return (
+
+ );
+}
diff --git a/webapp/src/components/OfferKindBadge.tsx b/webapp/src/components/OfferKindBadge.tsx
index 346f6d4a..e4d3aa75 100644
--- a/webapp/src/components/OfferKindBadge.tsx
+++ b/webapp/src/components/OfferKindBadge.tsx
@@ -6,18 +6,19 @@ import { OnlineIcon } from "~/components/icons/online";
export const OfferKindBadge = ({
kind,
variant,
+ chakraProps,
}: {
kind: Offer["kind"];
variant: "light" | "dark";
+ chakraProps?: Record;
}) => {
return (
{kind === "voucher" ? (
+ {text}
+
+
+ );
+}
diff --git a/webapp/src/components/icons/coupon.tsx b/webapp/src/components/icons/coupon.tsx
new file mode 100644
index 00000000..7b54d19e
--- /dev/null
+++ b/webapp/src/components/icons/coupon.tsx
@@ -0,0 +1,23 @@
+import { Icon, IconProps } from "@chakra-ui/react";
+
+export const CouponIcon = (props: IconProps) => {
+ return (
+
+
+
+
+ );
+};
diff --git a/webapp/src/components/modals/OfferActivationModal.tsx b/webapp/src/components/modals/OfferActivationModal.tsx
new file mode 100644
index 00000000..2dffe152
--- /dev/null
+++ b/webapp/src/components/modals/OfferActivationModal.tsx
@@ -0,0 +1,79 @@
+import { ArrowForwardIcon } from '@chakra-ui/icons';
+import {
+ Button,
+ Text,
+ List,
+ ListIcon,
+ ListItem,
+ ModalBody,
+ ModalContent,
+ ModalHeader
+} from '@chakra-ui/react';
+import { FiClock, FiGlobe, FiRotateCw, FiTag } from 'react-icons/fi';
+import { IconType } from 'react-icons/lib';
+import { TbBuildingStore } from 'react-icons/tb';
+import { OfferIncluded } from '~/server/api/routers/offer';
+
+const OfferActivationModal = ({
+ onClose,
+ onlyCgu,
+ offer,
+ mutateCouponToUser
+}: {
+ onClose: () => void;
+ onlyCgu?: boolean;
+ offer: OfferIncluded;
+ mutateCouponToUser: ({ offer_id }: { offer_id: number }) => void;
+}) => {
+ const validityToDate = new Date(offer.validityTo);
+
+ const cguItems: { icon: IconType; text: string; cross?: boolean }[] = [
+ { icon: FiGlobe, text: 'Utilisable en ligne' },
+ { icon: TbBuildingStore, text: 'À utiliser en magasin', cross: true },
+ {
+ icon: FiClock,
+ text: `À utiliser avant le ${validityToDate.toLocaleDateString()} !`
+ },
+ { icon: FiRotateCw, text: 'Utilisation illimité' },
+ { icon: FiTag, text: 'Non cumulable' }
+ ];
+
+ return (
+
+ {onlyCgu && Conditions d’utilisation}
+
+
+ {cguItems.map(({ icon, text, cross }, index) => (
+
+
+
+ {text}
+
+
+ ))}
+
+ : undefined}
+ onClick={() => {
+ if (!onlyCgu) mutateCouponToUser({ offer_id: offer.id });
+ onClose();
+ }}
+ >
+ {!onlyCgu ? 'Activer le code promo' : 'Fermer'}
+
+
+
+ );
+};
+
+export default OfferActivationModal;
diff --git a/webapp/src/components/wrappers/CategoriesWrapper.tsx b/webapp/src/components/wrappers/CategoriesWrapper.tsx
new file mode 100644
index 00000000..14972e6a
--- /dev/null
+++ b/webapp/src/components/wrappers/CategoriesWrapper.tsx
@@ -0,0 +1,49 @@
+import { ArrowBackIcon } from '@chakra-ui/icons';
+import { Button, Flex, Heading, SimpleGrid } from '@chakra-ui/react';
+import { useRouter } from 'next/router';
+import { ReactNode } from 'react';
+
+type CategoriesWrapperProps = {
+ children: ReactNode;
+ isLoading?: boolean;
+};
+
+const CategoriesWrapper = ({ children, isLoading }: CategoriesWrapperProps) => {
+ const router = useRouter();
+
+ return (
+
+
+
+
+ {children}
+
+
+ );
+};
+
+export default CategoriesWrapper;
diff --git a/webapp/src/components/wrappers/CategoryWrapper.tsx b/webapp/src/components/wrappers/CategoryWrapper.tsx
new file mode 100644
index 00000000..d0d54589
--- /dev/null
+++ b/webapp/src/components/wrappers/CategoryWrapper.tsx
@@ -0,0 +1,65 @@
+import { ChevronLeftIcon } from '@chakra-ui/icons';
+import { Box, Button, Flex, Heading } from '@chakra-ui/react';
+import { useRouter } from 'next/router';
+import { ReactNode } from 'react';
+import { CategoryIncluded } from '~/server/api/routers/category';
+import Image from 'next/image';
+
+type CategoryWrapperProps = {
+ children: ReactNode;
+ category: CategoryIncluded;
+};
+
+const CategoryWrapper = ({ children, category }: CategoryWrapperProps) => {
+ const router = useRouter();
+ return (
+
+
+
+
+ {children}
+
+
+ );
+};
+
+export default CategoryWrapper;
diff --git a/webapp/src/components/wrappers/CouponWrapper.tsx b/webapp/src/components/wrappers/CouponWrapper.tsx
new file mode 100644
index 00000000..fe086d0b
--- /dev/null
+++ b/webapp/src/components/wrappers/CouponWrapper.tsx
@@ -0,0 +1,110 @@
+import { CheckIcon } from '@chakra-ui/icons';
+import { Box, Button, Flex, Heading, Icon, Text } from '@chakra-ui/react';
+import { ReactNode } from 'react';
+import { FiLock, FiUnlock } from 'react-icons/fi';
+import { CouponIncluded } from '~/server/api/routers/coupon';
+
+type CouponWrapperProps = {
+ children: ReactNode;
+ coupon?: CouponIncluded;
+};
+
+const CouponWrapper = ({ children, coupon }: CouponWrapperProps) => {
+ return (
+
+
+ {coupon?.offer.title}
+
+
+
+
+ {coupon?.code ? coupon.code : '6FHDJFHEIDJF'}
+
+
+
+
+
+
+ {coupon && (
+
+
+
+ Code promo activé
+
+
+
+
+
+
+ Utilisable jusqu'au:{' '}
+
+ {new Date(coupon.offer.validityTo).toLocaleDateString()}
+
+
+
+ )}
+
+ {children}
+
+ );
+};
+
+export default CouponWrapper;
diff --git a/webapp/src/components/wrappers/OfferWrapper.tsx b/webapp/src/components/wrappers/OfferWrapper.tsx
new file mode 100644
index 00000000..e1cbbe4a
--- /dev/null
+++ b/webapp/src/components/wrappers/OfferWrapper.tsx
@@ -0,0 +1,74 @@
+import { ReactNode } from 'react';
+import Head from 'next/head';
+import { Button, Flex, Text, useTheme } from '@chakra-ui/react';
+import { ChevronLeftIcon } from '@chakra-ui/icons';
+import Image from 'next/image';
+import { OfferIncluded } from '~/server/api/routers/offer';
+import { dottedPattern } from '~/utils/chakra-theme';
+import { useRouter } from 'next/router';
+
+type OfferWrapperProps = {
+ children: ReactNode;
+ offer?: OfferIncluded;
+ isModalOpen?: boolean;
+};
+
+const OfferWrapper = ({ children, offer, isModalOpen }: OfferWrapperProps) => {
+ const router = useRouter();
+
+ const theme = useTheme();
+ const dotColor = theme.colors.bgWhite;
+
+ return (
+ <>
+
+
+
+
+
+
+ {children}
+
+ >
+ );
+};
+
+export default OfferWrapper;
diff --git a/webapp/src/layouts/DefaultLayout.tsx b/webapp/src/layouts/DefaultLayout.tsx
index b53a4a68..14bbdc61 100644
--- a/webapp/src/layouts/DefaultLayout.tsx
+++ b/webapp/src/layouts/DefaultLayout.tsx
@@ -5,13 +5,7 @@ import { ReactNode } from "react";
import InstallationBanner from "~/components/InstallationBanner";
import BottomNavigation from "~/components/BottomNavigation";
-export default function DefaultLayout({
- children,
- classname,
-}: {
- children: ReactNode;
- classname?: string;
-}) {
+export default function DefaultLayout({ children }: { children: ReactNode }) {
const pathname = usePathname();
return (
@@ -23,48 +17,25 @@ export default function DefaultLayout({
/* iOS */
-
+
-
-
+
-
- {children}
-
- {(pathname === "/dashboard" ||
- pathname === "/dashboard/offers" ||
- pathname === "/dashboard/account") && }
-
-
+ {children}
+
+ {(pathname === "/dashboard" ||
+ pathname === "/dashboard/offers" ||
+ pathname === "/dashboard/account") && }
+
>
);
diff --git a/webapp/src/middleware.ts b/webapp/src/middleware.ts
index 3965ce4c..8d6a68e4 100644
--- a/webapp/src/middleware.ts
+++ b/webapp/src/middleware.ts
@@ -4,14 +4,14 @@ import type { NextRequest } from "next/server";
// This function can be marked `async` if using `await` inside
export function middleware(request: NextRequest) {
if (
- !request.cookies.get(process.env.NEXT_PUBLIC_JWT_NAME as string) &&
+ !request.cookies.get(process.env.NEXT_PUBLIC_JWT_NAME ?? "cje-jwt") &&
request.nextUrl.pathname.startsWith("/dashboard")
) {
- return NextResponse.redirect(new URL("/login", request.url));
+ return NextResponse.redirect(new URL("/", request.url));
}
if (
- !!request.cookies.get(process.env.NEXT_PUBLIC_JWT_NAME as string) &&
+ !!request.cookies.get(process.env.NEXT_PUBLIC_JWT_NAME ?? "cje-jwt") &&
!request.nextUrl.pathname.startsWith("/dashboard")
) {
return NextResponse.redirect(new URL("/dashboard", request.url));
diff --git a/webapp/src/pages/_app.tsx b/webapp/src/pages/_app.tsx
index d559f0d7..532863a6 100644
--- a/webapp/src/pages/_app.tsx
+++ b/webapp/src/pages/_app.tsx
@@ -28,7 +28,7 @@ const MyApp: AppType = ({ Component, pageProps }) => {
}, []);
const getLayout = (children: ReactNode) => {
- if (pathname.startsWith("/admin")) {
+ if (pathname?.startsWith("/admin")) {
return children;
} else {
return {children};
diff --git a/webapp/src/pages/dashboard/account/index.tsx b/webapp/src/pages/dashboard/account/index.tsx
new file mode 100644
index 00000000..8a95627a
--- /dev/null
+++ b/webapp/src/pages/dashboard/account/index.tsx
@@ -0,0 +1,31 @@
+import { Box, Text } from '@chakra-ui/react';
+import { deleteCookie } from 'cookies-next';
+import Link from 'next/link';
+import { useRouter } from 'next/router';
+
+export default function Account() {
+ const router = useRouter();
+
+ const handleLogout = async () => {
+ await fetch('/api/users/logout', {
+ method: 'POST',
+ headers: {
+ 'Content-Type': 'application/json'
+ }
+ });
+
+ deleteCookie(process.env.NEXT_PUBLIC_JWT_NAME ?? 'cje-jwt');
+ router.reload();
+ router.push('/');
+ };
+
+ return (
+
+
+
+ Déconnexion
+
+
+
+ );
+}
diff --git a/webapp/src/pages/dashboard/categories.tsx b/webapp/src/pages/dashboard/categories.tsx
new file mode 100644
index 00000000..05dcb0de
--- /dev/null
+++ b/webapp/src/pages/dashboard/categories.tsx
@@ -0,0 +1,55 @@
+import { Center, Flex, Text } from '@chakra-ui/react';
+import Image from 'next/image';
+import Link from 'next/link';
+import { useRouter } from 'next/router';
+import LoadingLoader from '~/components/LoadingLoader';
+import CategoriesWrapper from '~/components/wrappers/CategoriesWrapper';
+import { api } from '~/utils/api';
+
+export default function Dashboard() {
+ const { data: resultCategories, isLoading: isLoadingCategories } =
+ api.category.getList.useQuery({
+ page: 1,
+ perPage: 50,
+ sort: 'createdAt'
+ });
+
+ const { data: categories } = resultCategories || {};
+
+ if (isLoadingCategories || !categories)
+ return (
+
+
+
+
+
+ );
+
+ return (
+
+ {categories.map(category => (
+
+
+
+
+ {category.label}
+
+
+
+ ))}
+
+ );
+}
diff --git a/webapp/src/pages/dashboard/category/[slug].tsx b/webapp/src/pages/dashboard/category/[slug].tsx
new file mode 100644
index 00000000..ad26044e
--- /dev/null
+++ b/webapp/src/pages/dashboard/category/[slug].tsx
@@ -0,0 +1,104 @@
+import { Center, Flex, Text } from '@chakra-ui/react';
+import Image from 'next/image';
+import Link from 'next/link';
+import { useRouter } from 'next/router';
+import LoadingLoader from '~/components/LoadingLoader';
+import { OfferKindBadge } from '~/components/OfferKindBadge';
+import CategoryWrapper from '~/components/wrappers/CategoryWrapper';
+import { api } from '~/utils/api';
+import { dottedPattern } from '~/utils/chakra-theme';
+
+export default function Dashboard() {
+ const router = useRouter();
+ const { slug } = router.query;
+
+ const { data: resultCategory } = api.category.getBySlug.useQuery(
+ {
+ slug: slug as string
+ },
+ { enabled: slug !== undefined }
+ );
+
+ const { data: category } = resultCategory || {};
+
+ const { data: resultOffers, isLoading: isLoadingOffers } =
+ api.offer.getList.useQuery(
+ {
+ page: 1,
+ perPage: 50,
+ sort: 'createdAt',
+ categoryId: category?.id
+ },
+ { enabled: category?.id !== undefined }
+ );
+
+ const { data: offers } = resultOffers || {};
+
+ if (!category) return;
+
+ if (isLoadingOffers || !offers)
+ return (
+
+
+
+
+
+ );
+
+ return (
+
+ {offers
+ ?.filter(offer => offer.kind === 'code')
+ ?.map(offer => (
+
+
+
+
+
+
+
+
+
+ {offer.partner.name}
+
+
+ {offer.title}
+
+
+
+
+
+ ))}
+
+ );
+}
diff --git a/webapp/src/pages/dashboard/index.tsx b/webapp/src/pages/dashboard/index.tsx
index 3ef1916c..ea4b0d3e 100644
--- a/webapp/src/pages/dashboard/index.tsx
+++ b/webapp/src/pages/dashboard/index.tsx
@@ -5,74 +5,31 @@ import { api } from "~/utils/api";
import { OfferKindBadge } from "~/components/OfferKindBadge";
export default function Dashboard() {
- const { data: resultCategories, isLoading: isLoadingCategories } =
- api.category.getList.useQuery({
- page: 1,
- perPage: 50,
- sort: "createdAt",
- });
+ // const { data: resultCategories, isLoading: isLoadingCategories } =
+ // api.category.getList.useQuery({
+ // page: 1,
+ // perPage: 50,
+ // sort: "createdAt",
+ // });
- const { data: resultOffers, isLoading: isLoadingOffers } =
- api.offer.getList.useQuery({
- page: 1,
- perPage: 50,
- });
+ // const { data: resultOffers, isLoading: isLoadingOffers } =
+ // api.offer.getList.useQuery({
+ // page: 1,
+ // perPage: 50,
+ // });
- const { data: categories } = resultCategories || {};
+ // const { data: categories } = resultCategories || {};
- const { data: offers } = resultOffers || {};
+ // const { data: offers } = resultOffers || {};
return (
-
-
-
-
- Catégories
-
-
-
- Tout voir
-
-
-
-
- {isLoadingCategories ? (
- Loading...
- ) : (
- categories?.map((category) => (
-
-
-
-
- {category.label}
-
- ))
- )}
-
-
+
+
+
+ Catégories
+
+
+ {/*
@@ -152,7 +109,7 @@ export default function Dashboard() {
))
)}
-
+ */}
);
}
diff --git a/webapp/src/pages/dashboard/offer/online/[id].tsx b/webapp/src/pages/dashboard/offer/online/[id].tsx
new file mode 100644
index 00000000..b51e9637
--- /dev/null
+++ b/webapp/src/pages/dashboard/offer/online/[id].tsx
@@ -0,0 +1,167 @@
+import {
+ Button,
+ ButtonGroup,
+ Center,
+ Divider,
+ Flex,
+ Icon,
+ Modal,
+ ModalOverlay,
+ useDisclosure,
+ useToast
+} from '@chakra-ui/react';
+import { useGSAP } from '@gsap/react';
+import Link from 'next/link';
+import { useRouter } from 'next/router';
+import { useState } from 'react';
+import { FiBook, FiCopy, FiLink } from 'react-icons/fi';
+import { IoCloseCircleOutline } from 'react-icons/io5';
+import LoadingLoader from '~/components/LoadingLoader';
+import ToastComponent from '~/components/ToastComponent';
+import { CouponIcon } from '~/components/icons/coupon';
+import OfferActivationModal from '~/components/modals/OfferActivationModal';
+import CouponWrapper from '~/components/wrappers/CouponWrapper';
+import OfferWrapper from '~/components/wrappers/OfferWrapper';
+import { couponAnimation } from '~/utils/animations';
+import { api } from '~/utils/api';
+
+export default function Dashboard() {
+ const router = useRouter();
+ const { id } = router.query;
+
+ const { data: resultOffer, isLoading: isLoadingOffer } =
+ api.offer.getById.useQuery(
+ {
+ id: parseInt(id as string)
+ },
+ { enabled: id !== undefined }
+ );
+
+ const {
+ data: resultCoupon,
+ isLoading: isLoadingCoupon,
+ refetch: refetchCoupon
+ } = api.coupon.getOne.useQuery(
+ {
+ offer_id: parseInt(id as string)
+ },
+ { enabled: id !== undefined }
+ );
+
+ const { data: offer } = resultOffer || {};
+ const { data: coupon } = resultCoupon || {};
+
+ const [isOnlyCgu, setIsOnlyCgu] = useState(false);
+
+ const {
+ mutate: mutateCouponToUser,
+ isLoading,
+ isSuccess
+ } = api.coupon.assignToUser.useMutation({
+ onSuccess: () => refetchCoupon()
+ });
+
+ const toast = useToast();
+
+ const {
+ isOpen: isModalOpen,
+ onOpen,
+ onClose
+ } = useDisclosure({
+ onClose: () => setIsOnlyCgu(false)
+ });
+
+ const handleCopyToClipboard = (text: string) => {
+ toast({
+ render: () => (
+
+ ),
+ duration: 2000
+ });
+ navigator.clipboard.writeText(text);
+ };
+
+ useGSAP(
+ () => {
+ couponAnimation(isSuccess, !!coupon);
+ },
+ { dependencies: [isLoadingCoupon, coupon, isSuccess] }
+ );
+
+ if (isLoadingOffer || !offer || isLoadingCoupon)
+ return (
+
+
+
+
+
+ );
+
+ return (
+
+
+ {!coupon ? (
+ <>
+ } py={8} onClick={onOpen}>
+ Activer le code promo
+
+
+ >
+ ) : (
+
+
+
+
+ )}
+
+
+
+
+ {offer && (
+
+ )}
+
+
+ );
+}
diff --git a/webapp/src/pages/index.tsx b/webapp/src/pages/index.tsx
index 07bbd335..dc78dbfe 100644
--- a/webapp/src/pages/index.tsx
+++ b/webapp/src/pages/index.tsx
@@ -1,108 +1,86 @@
-import {
- AspectRatio,
- Box,
- Button,
- Flex,
- Heading,
- Icon,
- Image,
- Text,
-} from "@chakra-ui/react";
-import { useRouter } from "next/router";
-import { useState } from "react";
+import { api } from "~/utils/api";
+import { Box, Button, Flex, Heading, Icon } from "@chakra-ui/react";
+import { useForm, type SubmitHandler } from "react-hook-form";
+import FormInput from "~/components/FormInput";
import { HiOutlineArrowLeft, HiOutlineArrowRight } from "react-icons/hi";
+import { useRouter } from "next/router";
+import { setCookie } from "cookies-next";
+
+type LoginForm = {
+ email: string;
+ password: string;
+};
export default function Home() {
const router = useRouter();
- const onBoardingItems = [
- {
- title: "Des réductions pour vous accompagner au quotidien",
- description:
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt",
- image: "/images/onboarding/discount.svg",
- },
- {
- title: "Générer facilement la promo associé à l’offre",
- description:
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt",
- image: "/images/onboarding/box.svg",
- },
- {
- title:
- "Utilisez la promo en ligne ou directement chez l’enseigne partenaire",
- description:
- "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt",
- image: "/images/onboarding/computer.svg",
+ const {
+ handleSubmit,
+ register,
+ formState: { errors },
+ } = useForm();
+
+ const { mutate: loginUser, isLoading } = api.user.login.useMutation({
+ onSuccess: async ({ data }) => {
+ setCookie(
+ process.env.NEXT_PUBLIC_JWT_NAME ?? "cje-jwt",
+ data.token || ""
+ );
+ router.reload();
+ router.push("/dashboard");
},
- ];
+ });
- const [onBoardingItemIndex, setOnBoardingItemIndex] = useState(0);
+ const handleLogin: SubmitHandler = async (values) => {
+ await loginUser(values);
+ };
return (
-
-
-
+
+
+ Connexion
-
- {onBoardingItems[onBoardingItemIndex]?.title}
-
-
- {onBoardingItems[onBoardingItemIndex]?.description}
-
-
-
- {
- if (onBoardingItemIndex !== 0)
- setOnBoardingItemIndex((prev) => prev - 1);
- }}
- color={onBoardingItemIndex === 0 ? "gray.300" : "primary.500"}
- />
-
- {
- if (onBoardingItemIndex !== onBoardingItems.length - 1) {
- setOnBoardingItemIndex((prev) => prev + 1);
- } else {
- router.push("/login");
- }
- }}
- color="primary.500"
- />
-
-
+
+
+
+ }
+ onClick={handleSubmit(handleLogin)}
+ isLoading={isLoading}
+ >
+ Se connecter
+
+
);
}
diff --git a/webapp/src/pages/login/index.tsx b/webapp/src/pages/login/index.tsx
deleted file mode 100644
index 8ccf9642..00000000
--- a/webapp/src/pages/login/index.tsx
+++ /dev/null
@@ -1,90 +0,0 @@
-import { api } from "~/utils/api";
-import { Box, Button, Flex, Heading, Icon } from "@chakra-ui/react";
-import { useForm, type SubmitHandler } from "react-hook-form";
-import FormInput from "~/components/FormInput";
-import { HiOutlineArrowLeft, HiOutlineArrowRight } from "react-icons/hi";
-import { useRouter } from "next/router";
-import { setCookie } from "cookies-next";
-
-type LoginForm = {
- email: string;
- password: string;
-};
-
-export default function Home() {
- const router = useRouter();
-
- const {
- handleSubmit,
- register,
- formState: { errors },
- } = useForm();
-
- const { mutate: loginUser, isLoading } = api.user.login.useMutation({
- onSuccess: async ({ data }) => {
- setCookie(process.env.NEXT_PUBLIC_JWT_NAME as string, data.token || "");
- router.reload();
- router.push("/dashboard");
- },
- });
-
- const handleLogin: SubmitHandler = async (values) => {
- await loginUser(values);
- };
-
- return (
-
-
- Connexion
-
-
-
-
-
-
- }
- iconSpacing={0}
- display={{ base: "flex", lg: "none" }}
- onClick={() => router.push("/")}
- />
- }
- onClick={handleSubmit(handleLogin)}
- isLoading={isLoading}
- >
- Se connecter
-
-
-
- );
-}
diff --git a/webapp/src/pages/register/index.tsx b/webapp/src/pages/register/index.tsx
deleted file mode 100644
index 05e1a68a..00000000
--- a/webapp/src/pages/register/index.tsx
+++ /dev/null
@@ -1,151 +0,0 @@
-import { api } from "~/utils/api";
-import {
- Box,
- Button,
- Flex,
- FormControl,
- FormErrorMessage,
- FormLabel,
- Heading,
- Input,
- useToast,
-} from "@chakra-ui/react";
-import { useForm, type SubmitHandler } from "react-hook-form";
-import { useRouter } from "next/router";
-
-type RegisterForm = {
- email: string;
- firstName: string;
- lastName: string;
- password: string;
- passwordConfirmation: string;
-};
-
-export default function Home() {
- const router = useRouter();
- const toast = useToast();
-
- const {
- handleSubmit,
- register,
- setError,
- getValues,
- formState: { errors },
- } = useForm();
-
- const { mutate: registerUser, isLoading } = api.user.register.useMutation({
- onSuccess: () => {
- toast({
- title: "Inscription réussie",
- description: "Vous pouvez maintenant vous connecter",
- status: "success",
- duration: 5000,
- isClosable: true,
- });
- router.push("/login");
- },
- onError: (error) => {
- console.log(error.data?.httpStatus);
- if (error.data?.httpStatus === 409) {
- setError("email", {
- type: "manual",
- message: "Cet email existe déjà",
- });
- console.log(errors);
- }
- },
- });
-
- const handleRegister: SubmitHandler = async (values) => {
- await registerUser(values);
- };
-
- return (
-
- Inscription
-
-
- Email
-
- {errors.email?.message}
-
-
- Prénom
-
- {errors.firstName?.message}
-
-
- Nom
-
- {errors.lastName?.message}
-
-
- Mot de passe
-
- {errors.password?.message}
-
-
-
- Confirmation mot de passe
-
-
- value === getValues("password") ||
- "Les mots de passe ne correspondent pas",
- })}
- />
-
- {errors.passwordConfirmation?.message}
-
-
-
-
-
-
-
- );
-}
diff --git a/webapp/src/payload/collections/Categorie.ts b/webapp/src/payload/collections/Categorie.ts
index a58625b9..0713e64c 100644
--- a/webapp/src/payload/collections/Categorie.ts
+++ b/webapp/src/payload/collections/Categorie.ts
@@ -6,6 +6,9 @@ export const Categories: CollectionConfig = {
singular: "Catégorie",
plural: "Catégories",
},
+ admin: {
+ useAsTitle: "label",
+ },
fields: [
{
name: "slug",
@@ -27,11 +30,5 @@ export const Categories: CollectionConfig = {
required: true,
relationTo: "media",
},
- {
- name: "color",
- type: "text",
- label: "Couleur",
- required: true,
- },
],
};
diff --git a/webapp/src/payload/collections/Coupon.ts b/webapp/src/payload/collections/Coupon.ts
new file mode 100644
index 00000000..70b09ab7
--- /dev/null
+++ b/webapp/src/payload/collections/Coupon.ts
@@ -0,0 +1,57 @@
+import dynamic from "next/dynamic";
+import type { Props } from "payload/components/views/List";
+import { type CollectionConfig } from "payload/types";
+
+const ImportCoupons = dynamic(
+ () => import("../components/ImportCoupons"),
+ {
+ ssr: false,
+ }
+);
+
+export const Coupons: CollectionConfig = {
+ slug: "coupons",
+ labels: {
+ singular: "Bon de réduction",
+ plural: "Bons de réduction",
+ },
+ fields: [
+ {
+ name: "code",
+ type: "text",
+ label: "Code",
+ required: true
+ },
+ {
+ name: "status",
+ type: "select",
+ label: "Statut",
+ options: [
+ { label: "Disponible", value: "available" },
+ { label: "Archivé", value: "archived" },
+ ],
+ defaultValue: "available",
+ required: true,
+ },
+ {
+ name: "user",
+ type: "relationship",
+ label: "Utilisateur",
+ relationTo: "users",
+ hasMany: false,
+ },
+ {
+ name: "offer",
+ type: "relationship",
+ label: "Offre",
+ relationTo: "offers",
+ hasMany: false,
+ required: true,
+ },
+ ],
+ admin: {
+ components: {
+ BeforeListTable: [ImportCoupons],
+ },
+ },
+};
diff --git a/webapp/src/payload/collections/Offer.ts b/webapp/src/payload/collections/Offer.ts
index 8d512f9c..b5cbf22a 100644
--- a/webapp/src/payload/collections/Offer.ts
+++ b/webapp/src/payload/collections/Offer.ts
@@ -6,6 +6,9 @@ export const Offers: CollectionConfig = {
singular: "Offre",
plural: "Offres",
},
+ admin: {
+ useAsTitle: "title",
+ },
fields: [
{
name: "title",
@@ -29,6 +32,12 @@ export const Offers: CollectionConfig = {
hasMany: false,
required: true,
},
+ {
+ name: "validityTo",
+ type: "date",
+ label: "Validité jusqu'au",
+ required: true,
+ },
{
type: "select",
name: "kind",
diff --git a/webapp/src/payload/collections/Partner.ts b/webapp/src/payload/collections/Partner.ts
index aacc6d40..a88f6bfb 100644
--- a/webapp/src/payload/collections/Partner.ts
+++ b/webapp/src/payload/collections/Partner.ts
@@ -6,6 +6,9 @@ export const Partners: CollectionConfig = {
singular: "Partenaire",
plural: "Partenaires",
},
+ admin: {
+ useAsTitle: "name",
+ },
fields: [
{
name: "name",
@@ -20,6 +23,18 @@ export const Partners: CollectionConfig = {
label: "Description",
required: true,
},
+ {
+ name: "url",
+ type: "text",
+ label: "URL",
+ required: true,
+ },
+ {
+ name: "color",
+ type: "text",
+ label: "Couleur",
+ required: true,
+ },
{
name: "icon",
type: "upload",
diff --git a/webapp/src/payload/collections/User.ts b/webapp/src/payload/collections/User.ts
index 76f79e48..8365cd88 100644
--- a/webapp/src/payload/collections/User.ts
+++ b/webapp/src/payload/collections/User.ts
@@ -7,6 +7,9 @@ export const Users: CollectionConfig = {
singular: "Utilisateur",
plural: "Utilisateurs",
},
+ admin: {
+ useAsTitle: "email",
+ },
fields: [
{
name: "email",
diff --git a/webapp/src/payload/components/ImportCoupons.tsx b/webapp/src/payload/components/ImportCoupons.tsx
new file mode 100644
index 00000000..a65f8a9e
--- /dev/null
+++ b/webapp/src/payload/components/ImportCoupons.tsx
@@ -0,0 +1,184 @@
+import { QuestionOutlineIcon } from "@chakra-ui/icons";
+import {
+ Box,
+ Button,
+ Flex,
+ FormControl,
+ Heading,
+ Select,
+ Tooltip,
+} from "@chakra-ui/react";
+import { Modal, useModal } from "@faceless-ui/modal";
+import { useMutation } from "@tanstack/react-query";
+import Papa from "papaparse";
+import { MinimalTemplate } from "payload/components/templates";
+import type { Props } from "payload/components/views/List";
+import usePayloadAPI from "payload/dist/admin/hooks/usePayloadAPI";
+import React, { useState } from "react";
+import { toast } from "react-toastify";
+import { OfferIncluded } from "~/server/api/routers/offer";
+import { api } from "~/utils/api";
+import { Coupon } from "../payload-types";
+
+export type ImportCouponsProps = {};
+
+const ImportCoupons = ({ hasCreatePermission, resetParams }: Props) => {
+ const { toggleModal } = useModal();
+ const modalSlug = "modal-import-coupons";
+
+ const [csvFileValue, setCsvFileValue] = useState("");
+ const [offerId, setOfferId] = useState();
+ const [coupons, setCoupons] = useState([]);
+
+ const [
+ {
+ data: { docs },
+ },
+ ] = usePayloadAPI(`/api/offers`, {
+ initialParams: {
+ page: 1,
+ limit: 1000,
+ },
+ });
+ const offers = docs as OfferIncluded[];
+
+ const createCoupons = useMutation({
+ mutationFn: (payload: Coupon) => {
+ return fetch("/api/coupons", {
+ method: "POST",
+ credentials: "include",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify(payload),
+ });
+ },
+ });
+
+ const handleFileChange = (event: React.ChangeEvent) => {
+ const file = event.target.files?.[0];
+
+ if (file) {
+ setCsvFileValue(undefined);
+ Papa.parse(file, {
+ complete: (result) => {
+ const couponsToCreate = result.data
+ .filter((row: any) => row.code)
+ .map((row: any) => {
+ return {
+ code: row.code as string,
+ status: "available",
+ offer: -1,
+ } as Coupon;
+ });
+
+ if (!couponsToCreate.length) {
+ toast.error("Erreur dans le format du CSV");
+ return;
+ }
+
+ setCoupons(couponsToCreate);
+ toggleModal(modalSlug);
+ },
+ header: true,
+ dynamicTyping: true,
+ });
+ }
+ };
+
+ const validate = () => {
+ if (!offerId) return;
+
+ if (coupons.length) {
+ const promises: Promise[] = [];
+ coupons.forEach((coupon) => {
+ promises.push(createCoupons.mutateAsync({ ...coupon, offer: offerId }));
+ });
+ Promise.all(promises).then((responses) => {
+ const okRequestsCount = responses.filter((r) => r.ok).length;
+ const koRequestsCount = responses.filter((r) => !r.ok).length;
+
+ if (okRequestsCount)
+ toast.success(`${okRequestsCount} bons de réduction importés`);
+
+ if (koRequestsCount)
+ toast.error(`Erreur à l'import bons de réduction en base de donnée (${koRequestsCount} bons de réduction)`);
+
+ setCoupons([]);
+ resetParams();
+ });
+ }
+
+ toggleModal(modalSlug);
+ };
+
+ if (!hasCreatePermission || !offers) return;
+
+ return (
+
+ {
+ setCsvFileValue("");
+ }}
+ style={{ display: "none" }}
+ />
+
+
+
+
+
+
+
+ Offre pour laquelle importer des bons de réduction :
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default ImportCoupons;
diff --git a/webapp/src/payload/migrations/20240125_091516.json b/webapp/src/payload/migrations/20240125_091516.json
new file mode 100644
index 00000000..f0230cb9
--- /dev/null
+++ b/webapp/src/payload/migrations/20240125_091516.json
@@ -0,0 +1,1162 @@
+{
+ "id": "eacd7eb3-0523-4147-aa2f-7ab1d2c342d1",
+ "prevId": "00000000-0000-0000-0000-000000000000",
+ "version": "5",
+ "dialect": "pg",
+ "tables": {
+ "admins": {
+ "name": "admins",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "first_name": {
+ "name": "first_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "last_name": {
+ "name": "last_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "email": {
+ "name": "email",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "reset_password_token": {
+ "name": "reset_password_token",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "reset_password_expiration": {
+ "name": "reset_password_expiration",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "salt": {
+ "name": "salt",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "hash": {
+ "name": "hash",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "login_attempts": {
+ "name": "login_attempts",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "lock_until": {
+ "name": "lock_until",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ },
+ "email_idx": {
+ "name": "email_idx",
+ "columns": [
+ "email"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "users": {
+ "name": "users",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "first_name": {
+ "name": "first_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "last_name": {
+ "name": "last_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "email": {
+ "name": "email",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "reset_password_token": {
+ "name": "reset_password_token",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "reset_password_expiration": {
+ "name": "reset_password_expiration",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "salt": {
+ "name": "salt",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "hash": {
+ "name": "hash",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "login_attempts": {
+ "name": "login_attempts",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "lock_until": {
+ "name": "lock_until",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ },
+ "email_idx": {
+ "name": "email_idx",
+ "columns": [
+ "email"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "media": {
+ "name": "media",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "alt": {
+ "name": "alt",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filename": {
+ "name": "filename",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "mime_type": {
+ "name": "mime_type",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filesize": {
+ "name": "filesize",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "width": {
+ "name": "width",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "height": {
+ "name": "height",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ },
+ "filename_idx": {
+ "name": "filename_idx",
+ "columns": [
+ "filename"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "categories": {
+ "name": "categories",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "label": {
+ "name": "label",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "slug_idx": {
+ "name": "slug_idx",
+ "columns": [
+ "slug"
+ ],
+ "isUnique": true
+ },
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "categories_rels": {
+ "name": "categories_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "media_id": {
+ "name": "media_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "order_idx": {
+ "name": "order_idx",
+ "columns": [
+ "order"
+ ],
+ "isUnique": false
+ },
+ "parent_idx": {
+ "name": "parent_idx",
+ "columns": [
+ "parent_id"
+ ],
+ "isUnique": false
+ },
+ "path_idx": {
+ "name": "path_idx",
+ "columns": [
+ "path"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "categories_rels_parent_id_categories_id_fk": {
+ "name": "categories_rels_parent_id_categories_id_fk",
+ "tableFrom": "categories_rels",
+ "tableTo": "categories",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "categories_rels_media_id_media_id_fk": {
+ "name": "categories_rels_media_id_media_id_fk",
+ "tableFrom": "categories_rels",
+ "tableTo": "media",
+ "columnsFrom": [
+ "media_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "partners": {
+ "name": "partners",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "color": {
+ "name": "color",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "name_idx": {
+ "name": "name_idx",
+ "columns": [
+ "name"
+ ],
+ "isUnique": true
+ },
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "partners_rels": {
+ "name": "partners_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "media_id": {
+ "name": "media_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "order_idx": {
+ "name": "order_idx",
+ "columns": [
+ "order"
+ ],
+ "isUnique": false
+ },
+ "parent_idx": {
+ "name": "parent_idx",
+ "columns": [
+ "parent_id"
+ ],
+ "isUnique": false
+ },
+ "path_idx": {
+ "name": "path_idx",
+ "columns": [
+ "path"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "partners_rels_parent_id_partners_id_fk": {
+ "name": "partners_rels_parent_id_partners_id_fk",
+ "tableFrom": "partners_rels",
+ "tableTo": "partners",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "partners_rels_media_id_media_id_fk": {
+ "name": "partners_rels_media_id_media_id_fk",
+ "tableFrom": "partners_rels",
+ "tableTo": "media",
+ "columnsFrom": [
+ "media_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "offers": {
+ "name": "offers",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "validity_to": {
+ "name": "validity_to",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "kind": {
+ "name": "kind",
+ "type": "enum_offers_kind",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "offers_rels": {
+ "name": "offers_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "partners_id": {
+ "name": "partners_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "categories_id": {
+ "name": "categories_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "order_idx": {
+ "name": "order_idx",
+ "columns": [
+ "order"
+ ],
+ "isUnique": false
+ },
+ "parent_idx": {
+ "name": "parent_idx",
+ "columns": [
+ "parent_id"
+ ],
+ "isUnique": false
+ },
+ "path_idx": {
+ "name": "path_idx",
+ "columns": [
+ "path"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "offers_rels_parent_id_offers_id_fk": {
+ "name": "offers_rels_parent_id_offers_id_fk",
+ "tableFrom": "offers_rels",
+ "tableTo": "offers",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "offers_rels_partners_id_partners_id_fk": {
+ "name": "offers_rels_partners_id_partners_id_fk",
+ "tableFrom": "offers_rels",
+ "tableTo": "partners",
+ "columnsFrom": [
+ "partners_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "offers_rels_categories_id_categories_id_fk": {
+ "name": "offers_rels_categories_id_categories_id_fk",
+ "tableFrom": "offers_rels",
+ "tableTo": "categories",
+ "columnsFrom": [
+ "categories_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "coupons": {
+ "name": "coupons",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "code": {
+ "name": "code",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "status": {
+ "name": "status",
+ "type": "enum_coupons_status",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "code_idx": {
+ "name": "code_idx",
+ "columns": [
+ "code"
+ ],
+ "isUnique": true
+ },
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "coupons_rels": {
+ "name": "coupons_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "users_id": {
+ "name": "users_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "offers_id": {
+ "name": "offers_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "order_idx": {
+ "name": "order_idx",
+ "columns": [
+ "order"
+ ],
+ "isUnique": false
+ },
+ "parent_idx": {
+ "name": "parent_idx",
+ "columns": [
+ "parent_id"
+ ],
+ "isUnique": false
+ },
+ "path_idx": {
+ "name": "path_idx",
+ "columns": [
+ "path"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "coupons_rels_parent_id_coupons_id_fk": {
+ "name": "coupons_rels_parent_id_coupons_id_fk",
+ "tableFrom": "coupons_rels",
+ "tableTo": "coupons",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "coupons_rels_users_id_users_id_fk": {
+ "name": "coupons_rels_users_id_users_id_fk",
+ "tableFrom": "coupons_rels",
+ "tableTo": "users",
+ "columnsFrom": [
+ "users_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "coupons_rels_offers_id_offers_id_fk": {
+ "name": "coupons_rels_offers_id_offers_id_fk",
+ "tableFrom": "coupons_rels",
+ "tableTo": "offers",
+ "columnsFrom": [
+ "offers_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "payload_preferences": {
+ "name": "payload_preferences",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "value": {
+ "name": "value",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "payload_preferences_rels": {
+ "name": "payload_preferences_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "admins_id": {
+ "name": "admins_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "users_id": {
+ "name": "users_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "order_idx": {
+ "name": "order_idx",
+ "columns": [
+ "order"
+ ],
+ "isUnique": false
+ },
+ "parent_idx": {
+ "name": "parent_idx",
+ "columns": [
+ "parent_id"
+ ],
+ "isUnique": false
+ },
+ "path_idx": {
+ "name": "path_idx",
+ "columns": [
+ "path"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payload_preferences_rels_parent_id_payload_preferences_id_fk": {
+ "name": "payload_preferences_rels_parent_id_payload_preferences_id_fk",
+ "tableFrom": "payload_preferences_rels",
+ "tableTo": "payload_preferences",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_preferences_rels_admins_id_admins_id_fk": {
+ "name": "payload_preferences_rels_admins_id_admins_id_fk",
+ "tableFrom": "payload_preferences_rels",
+ "tableTo": "admins",
+ "columnsFrom": [
+ "admins_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_preferences_rels_users_id_users_id_fk": {
+ "name": "payload_preferences_rels_users_id_users_id_fk",
+ "tableFrom": "payload_preferences_rels",
+ "tableTo": "users",
+ "columnsFrom": [
+ "users_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "payload_migrations": {
+ "name": "payload_migrations",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "batch": {
+ "name": "batch",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ }
+ },
+ "enums": {
+ "_locales": {
+ "name": "_locales",
+ "values": {
+ "fr": "fr"
+ }
+ },
+ "enum_offers_kind": {
+ "name": "enum_offers_kind",
+ "values": {
+ "voucher": "voucher",
+ "code": "code"
+ }
+ },
+ "enum_coupons_status": {
+ "name": "enum_coupons_status",
+ "values": {
+ "available": "available",
+ "archived": "archived"
+ }
+ }
+ },
+ "schemas": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ }
+}
\ No newline at end of file
diff --git a/webapp/src/payload/migrations/20240125_091516.ts b/webapp/src/payload/migrations/20240125_091516.ts
new file mode 100644
index 00000000..92614682
--- /dev/null
+++ b/webapp/src/payload/migrations/20240125_091516.ts
@@ -0,0 +1,291 @@
+import { MigrateUpArgs, MigrateDownArgs } from '@payloadcms/db-postgres'
+import { sql } from 'drizzle-orm'
+
+export async function up({ payload }: MigrateUpArgs): Promise {
+await payload.db.drizzle.execute(sql`
+
+DO $$ BEGIN
+ CREATE TYPE "_locales" AS ENUM('fr');
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+DO $$ BEGIN
+ CREATE TYPE "enum_offers_kind" AS ENUM('voucher', 'code');
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+DO $$ BEGIN
+ CREATE TYPE "enum_coupons_status" AS ENUM('available', 'archived');
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+CREATE TABLE IF NOT EXISTS "admins" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "first_name" varchar NOT NULL,
+ "last_name" varchar NOT NULL,
+ "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
+ "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
+ "email" varchar NOT NULL,
+ "reset_password_token" varchar,
+ "reset_password_expiration" timestamp(3) with time zone,
+ "salt" varchar,
+ "hash" varchar,
+ "login_attempts" numeric,
+ "lock_until" timestamp(3) with time zone
+);
+
+CREATE TABLE IF NOT EXISTS "users" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "first_name" varchar NOT NULL,
+ "last_name" varchar NOT NULL,
+ "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
+ "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
+ "email" varchar NOT NULL,
+ "reset_password_token" varchar,
+ "reset_password_expiration" timestamp(3) with time zone,
+ "salt" varchar,
+ "hash" varchar,
+ "login_attempts" numeric,
+ "lock_until" timestamp(3) with time zone
+);
+
+CREATE TABLE IF NOT EXISTS "media" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "alt" varchar,
+ "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
+ "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
+ "url" varchar,
+ "filename" varchar,
+ "mime_type" varchar,
+ "filesize" numeric,
+ "width" numeric,
+ "height" numeric
+);
+
+CREATE TABLE IF NOT EXISTS "categories" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "slug" varchar NOT NULL,
+ "label" varchar NOT NULL,
+ "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
+ "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS "categories_rels" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "order" integer,
+ "parent_id" integer NOT NULL,
+ "path" varchar NOT NULL,
+ "media_id" integer
+);
+
+CREATE TABLE IF NOT EXISTS "partners" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "name" varchar NOT NULL,
+ "description" varchar NOT NULL,
+ "url" varchar NOT NULL,
+ "color" varchar NOT NULL,
+ "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
+ "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS "partners_rels" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "order" integer,
+ "parent_id" integer NOT NULL,
+ "path" varchar NOT NULL,
+ "media_id" integer
+);
+
+CREATE TABLE IF NOT EXISTS "offers" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "title" varchar NOT NULL,
+ "validity_to" timestamp(3) with time zone NOT NULL,
+ "kind" "enum_offers_kind" NOT NULL,
+ "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
+ "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS "offers_rels" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "order" integer,
+ "parent_id" integer NOT NULL,
+ "path" varchar NOT NULL,
+ "partners_id" integer,
+ "categories_id" integer
+);
+
+CREATE TABLE IF NOT EXISTS "coupons" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "code" varchar NOT NULL,
+ "status" "enum_coupons_status" NOT NULL,
+ "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
+ "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS "coupons_rels" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "order" integer,
+ "parent_id" integer NOT NULL,
+ "path" varchar NOT NULL,
+ "users_id" integer,
+ "offers_id" integer
+);
+
+CREATE TABLE IF NOT EXISTS "payload_preferences" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "key" varchar,
+ "value" jsonb,
+ "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
+ "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
+);
+
+CREATE TABLE IF NOT EXISTS "payload_preferences_rels" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "order" integer,
+ "parent_id" integer NOT NULL,
+ "path" varchar NOT NULL,
+ "admins_id" integer,
+ "users_id" integer
+);
+
+CREATE TABLE IF NOT EXISTS "payload_migrations" (
+ "id" serial PRIMARY KEY NOT NULL,
+ "name" varchar,
+ "batch" numeric,
+ "updated_at" timestamp(3) with time zone DEFAULT now() NOT NULL,
+ "created_at" timestamp(3) with time zone DEFAULT now() NOT NULL
+);
+
+CREATE INDEX IF NOT EXISTS "created_at_idx" ON "admins" ("created_at");
+CREATE UNIQUE INDEX IF NOT EXISTS "email_idx" ON "admins" ("email");
+CREATE INDEX IF NOT EXISTS "created_at_idx" ON "users" ("created_at");
+CREATE UNIQUE INDEX IF NOT EXISTS "email_idx" ON "users" ("email");
+CREATE INDEX IF NOT EXISTS "created_at_idx" ON "media" ("created_at");
+CREATE UNIQUE INDEX IF NOT EXISTS "filename_idx" ON "media" ("filename");
+CREATE UNIQUE INDEX IF NOT EXISTS "slug_idx" ON "categories" ("slug");
+CREATE INDEX IF NOT EXISTS "created_at_idx" ON "categories" ("created_at");
+CREATE INDEX IF NOT EXISTS "order_idx" ON "categories_rels" ("order");
+CREATE INDEX IF NOT EXISTS "parent_idx" ON "categories_rels" ("parent_id");
+CREATE INDEX IF NOT EXISTS "path_idx" ON "categories_rels" ("path");
+CREATE UNIQUE INDEX IF NOT EXISTS "name_idx" ON "partners" ("name");
+CREATE INDEX IF NOT EXISTS "created_at_idx" ON "partners" ("created_at");
+CREATE INDEX IF NOT EXISTS "order_idx" ON "partners_rels" ("order");
+CREATE INDEX IF NOT EXISTS "parent_idx" ON "partners_rels" ("parent_id");
+CREATE INDEX IF NOT EXISTS "path_idx" ON "partners_rels" ("path");
+CREATE INDEX IF NOT EXISTS "created_at_idx" ON "offers" ("created_at");
+CREATE INDEX IF NOT EXISTS "order_idx" ON "offers_rels" ("order");
+CREATE INDEX IF NOT EXISTS "parent_idx" ON "offers_rels" ("parent_id");
+CREATE INDEX IF NOT EXISTS "path_idx" ON "offers_rels" ("path");
+CREATE UNIQUE INDEX IF NOT EXISTS "code_idx" ON "coupons" ("code");
+CREATE INDEX IF NOT EXISTS "created_at_idx" ON "coupons" ("created_at");
+CREATE INDEX IF NOT EXISTS "order_idx" ON "coupons_rels" ("order");
+CREATE INDEX IF NOT EXISTS "parent_idx" ON "coupons_rels" ("parent_id");
+CREATE INDEX IF NOT EXISTS "path_idx" ON "coupons_rels" ("path");
+CREATE INDEX IF NOT EXISTS "created_at_idx" ON "payload_preferences" ("created_at");
+CREATE INDEX IF NOT EXISTS "order_idx" ON "payload_preferences_rels" ("order");
+CREATE INDEX IF NOT EXISTS "parent_idx" ON "payload_preferences_rels" ("parent_id");
+CREATE INDEX IF NOT EXISTS "path_idx" ON "payload_preferences_rels" ("path");
+CREATE INDEX IF NOT EXISTS "created_at_idx" ON "payload_migrations" ("created_at");
+DO $$ BEGIN
+ ALTER TABLE "categories_rels" ADD CONSTRAINT "categories_rels_parent_id_categories_id_fk" FOREIGN KEY ("parent_id") REFERENCES "categories"("id") ON DELETE cascade ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+DO $$ BEGIN
+ ALTER TABLE "categories_rels" ADD CONSTRAINT "categories_rels_media_id_media_id_fk" FOREIGN KEY ("media_id") REFERENCES "media"("id") ON DELETE cascade ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+DO $$ BEGIN
+ ALTER TABLE "partners_rels" ADD CONSTRAINT "partners_rels_parent_id_partners_id_fk" FOREIGN KEY ("parent_id") REFERENCES "partners"("id") ON DELETE cascade ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+DO $$ BEGIN
+ ALTER TABLE "partners_rels" ADD CONSTRAINT "partners_rels_media_id_media_id_fk" FOREIGN KEY ("media_id") REFERENCES "media"("id") ON DELETE cascade ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+DO $$ BEGIN
+ ALTER TABLE "offers_rels" ADD CONSTRAINT "offers_rels_parent_id_offers_id_fk" FOREIGN KEY ("parent_id") REFERENCES "offers"("id") ON DELETE cascade ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+DO $$ BEGIN
+ ALTER TABLE "offers_rels" ADD CONSTRAINT "offers_rels_partners_id_partners_id_fk" FOREIGN KEY ("partners_id") REFERENCES "partners"("id") ON DELETE cascade ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+DO $$ BEGIN
+ ALTER TABLE "offers_rels" ADD CONSTRAINT "offers_rels_categories_id_categories_id_fk" FOREIGN KEY ("categories_id") REFERENCES "categories"("id") ON DELETE cascade ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+DO $$ BEGIN
+ ALTER TABLE "coupons_rels" ADD CONSTRAINT "coupons_rels_parent_id_coupons_id_fk" FOREIGN KEY ("parent_id") REFERENCES "coupons"("id") ON DELETE cascade ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+DO $$ BEGIN
+ ALTER TABLE "coupons_rels" ADD CONSTRAINT "coupons_rels_users_id_users_id_fk" FOREIGN KEY ("users_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+DO $$ BEGIN
+ ALTER TABLE "coupons_rels" ADD CONSTRAINT "coupons_rels_offers_id_offers_id_fk" FOREIGN KEY ("offers_id") REFERENCES "offers"("id") ON DELETE cascade ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+DO $$ BEGIN
+ ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_parent_id_payload_preferences_id_fk" FOREIGN KEY ("parent_id") REFERENCES "payload_preferences"("id") ON DELETE cascade ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+DO $$ BEGIN
+ ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_admins_id_admins_id_fk" FOREIGN KEY ("admins_id") REFERENCES "admins"("id") ON DELETE cascade ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+
+DO $$ BEGIN
+ ALTER TABLE "payload_preferences_rels" ADD CONSTRAINT "payload_preferences_rels_users_id_users_id_fk" FOREIGN KEY ("users_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
+EXCEPTION
+ WHEN duplicate_object THEN null;
+END $$;
+`);
+
+};
+
+export async function down({ payload }: MigrateDownArgs): Promise {
+await payload.db.drizzle.execute(sql`
+
+DROP TABLE "admins";
+DROP TABLE "users";
+DROP TABLE "media";
+DROP TABLE "categories";
+DROP TABLE "categories_rels";
+DROP TABLE "partners";
+DROP TABLE "partners_rels";
+DROP TABLE "offers";
+DROP TABLE "offers_rels";
+DROP TABLE "coupons";
+DROP TABLE "coupons_rels";
+DROP TABLE "payload_preferences";
+DROP TABLE "payload_preferences_rels";
+DROP TABLE "payload_migrations";`);
+
+};
diff --git a/webapp/src/payload/migrations/20240126_145518.json b/webapp/src/payload/migrations/20240126_145518.json
new file mode 100644
index 00000000..97a93a05
--- /dev/null
+++ b/webapp/src/payload/migrations/20240126_145518.json
@@ -0,0 +1,1155 @@
+{
+ "id": "170fa0ed-2d42-47a4-8b4e-357995933d5c",
+ "prevId": "00000000-0000-0000-0000-000000000000",
+ "version": "5",
+ "dialect": "pg",
+ "tables": {
+ "admins": {
+ "name": "admins",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "first_name": {
+ "name": "first_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "last_name": {
+ "name": "last_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "email": {
+ "name": "email",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "reset_password_token": {
+ "name": "reset_password_token",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "reset_password_expiration": {
+ "name": "reset_password_expiration",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "salt": {
+ "name": "salt",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "hash": {
+ "name": "hash",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "login_attempts": {
+ "name": "login_attempts",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "lock_until": {
+ "name": "lock_until",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ },
+ "email_idx": {
+ "name": "email_idx",
+ "columns": [
+ "email"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "users": {
+ "name": "users",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "first_name": {
+ "name": "first_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "last_name": {
+ "name": "last_name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "email": {
+ "name": "email",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "reset_password_token": {
+ "name": "reset_password_token",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "reset_password_expiration": {
+ "name": "reset_password_expiration",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "salt": {
+ "name": "salt",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "hash": {
+ "name": "hash",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "login_attempts": {
+ "name": "login_attempts",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "lock_until": {
+ "name": "lock_until",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ },
+ "email_idx": {
+ "name": "email_idx",
+ "columns": [
+ "email"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "media": {
+ "name": "media",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "alt": {
+ "name": "alt",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filename": {
+ "name": "filename",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "mime_type": {
+ "name": "mime_type",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "filesize": {
+ "name": "filesize",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "width": {
+ "name": "width",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "height": {
+ "name": "height",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ },
+ "filename_idx": {
+ "name": "filename_idx",
+ "columns": [
+ "filename"
+ ],
+ "isUnique": true
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "categories": {
+ "name": "categories",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "slug": {
+ "name": "slug",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "label": {
+ "name": "label",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "slug_idx": {
+ "name": "slug_idx",
+ "columns": [
+ "slug"
+ ],
+ "isUnique": true
+ },
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "categories_rels": {
+ "name": "categories_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "media_id": {
+ "name": "media_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "order_idx": {
+ "name": "order_idx",
+ "columns": [
+ "order"
+ ],
+ "isUnique": false
+ },
+ "parent_idx": {
+ "name": "parent_idx",
+ "columns": [
+ "parent_id"
+ ],
+ "isUnique": false
+ },
+ "path_idx": {
+ "name": "path_idx",
+ "columns": [
+ "path"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "categories_rels_parent_id_categories_id_fk": {
+ "name": "categories_rels_parent_id_categories_id_fk",
+ "tableFrom": "categories_rels",
+ "tableTo": "categories",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "categories_rels_media_id_media_id_fk": {
+ "name": "categories_rels_media_id_media_id_fk",
+ "tableFrom": "categories_rels",
+ "tableTo": "media",
+ "columnsFrom": [
+ "media_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "partners": {
+ "name": "partners",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "description": {
+ "name": "description",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "url": {
+ "name": "url",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "color": {
+ "name": "color",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "name_idx": {
+ "name": "name_idx",
+ "columns": [
+ "name"
+ ],
+ "isUnique": true
+ },
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "partners_rels": {
+ "name": "partners_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "media_id": {
+ "name": "media_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "order_idx": {
+ "name": "order_idx",
+ "columns": [
+ "order"
+ ],
+ "isUnique": false
+ },
+ "parent_idx": {
+ "name": "parent_idx",
+ "columns": [
+ "parent_id"
+ ],
+ "isUnique": false
+ },
+ "path_idx": {
+ "name": "path_idx",
+ "columns": [
+ "path"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "partners_rels_parent_id_partners_id_fk": {
+ "name": "partners_rels_parent_id_partners_id_fk",
+ "tableFrom": "partners_rels",
+ "tableTo": "partners",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "partners_rels_media_id_media_id_fk": {
+ "name": "partners_rels_media_id_media_id_fk",
+ "tableFrom": "partners_rels",
+ "tableTo": "media",
+ "columnsFrom": [
+ "media_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "offers": {
+ "name": "offers",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "title": {
+ "name": "title",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "validity_to": {
+ "name": "validity_to",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "kind": {
+ "name": "kind",
+ "type": "enum_offers_kind",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "offers_rels": {
+ "name": "offers_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "partners_id": {
+ "name": "partners_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "categories_id": {
+ "name": "categories_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "order_idx": {
+ "name": "order_idx",
+ "columns": [
+ "order"
+ ],
+ "isUnique": false
+ },
+ "parent_idx": {
+ "name": "parent_idx",
+ "columns": [
+ "parent_id"
+ ],
+ "isUnique": false
+ },
+ "path_idx": {
+ "name": "path_idx",
+ "columns": [
+ "path"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "offers_rels_parent_id_offers_id_fk": {
+ "name": "offers_rels_parent_id_offers_id_fk",
+ "tableFrom": "offers_rels",
+ "tableTo": "offers",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "offers_rels_partners_id_partners_id_fk": {
+ "name": "offers_rels_partners_id_partners_id_fk",
+ "tableFrom": "offers_rels",
+ "tableTo": "partners",
+ "columnsFrom": [
+ "partners_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "offers_rels_categories_id_categories_id_fk": {
+ "name": "offers_rels_categories_id_categories_id_fk",
+ "tableFrom": "offers_rels",
+ "tableTo": "categories",
+ "columnsFrom": [
+ "categories_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "coupons": {
+ "name": "coupons",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "code": {
+ "name": "code",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "status": {
+ "name": "status",
+ "type": "enum_coupons_status",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "coupons_rels": {
+ "name": "coupons_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "users_id": {
+ "name": "users_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "offers_id": {
+ "name": "offers_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "order_idx": {
+ "name": "order_idx",
+ "columns": [
+ "order"
+ ],
+ "isUnique": false
+ },
+ "parent_idx": {
+ "name": "parent_idx",
+ "columns": [
+ "parent_id"
+ ],
+ "isUnique": false
+ },
+ "path_idx": {
+ "name": "path_idx",
+ "columns": [
+ "path"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "coupons_rels_parent_id_coupons_id_fk": {
+ "name": "coupons_rels_parent_id_coupons_id_fk",
+ "tableFrom": "coupons_rels",
+ "tableTo": "coupons",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "coupons_rels_users_id_users_id_fk": {
+ "name": "coupons_rels_users_id_users_id_fk",
+ "tableFrom": "coupons_rels",
+ "tableTo": "users",
+ "columnsFrom": [
+ "users_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "coupons_rels_offers_id_offers_id_fk": {
+ "name": "coupons_rels_offers_id_offers_id_fk",
+ "tableFrom": "coupons_rels",
+ "tableTo": "offers",
+ "columnsFrom": [
+ "offers_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "payload_preferences": {
+ "name": "payload_preferences",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "key": {
+ "name": "key",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "value": {
+ "name": "value",
+ "type": "jsonb",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "payload_preferences_rels": {
+ "name": "payload_preferences_rels",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "order": {
+ "name": "order",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "parent_id": {
+ "name": "parent_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "path": {
+ "name": "path",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": true
+ },
+ "admins_id": {
+ "name": "admins_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "users_id": {
+ "name": "users_id",
+ "type": "integer",
+ "primaryKey": false,
+ "notNull": false
+ }
+ },
+ "indexes": {
+ "order_idx": {
+ "name": "order_idx",
+ "columns": [
+ "order"
+ ],
+ "isUnique": false
+ },
+ "parent_idx": {
+ "name": "parent_idx",
+ "columns": [
+ "parent_id"
+ ],
+ "isUnique": false
+ },
+ "path_idx": {
+ "name": "path_idx",
+ "columns": [
+ "path"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {
+ "payload_preferences_rels_parent_id_payload_preferences_id_fk": {
+ "name": "payload_preferences_rels_parent_id_payload_preferences_id_fk",
+ "tableFrom": "payload_preferences_rels",
+ "tableTo": "payload_preferences",
+ "columnsFrom": [
+ "parent_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_preferences_rels_admins_id_admins_id_fk": {
+ "name": "payload_preferences_rels_admins_id_admins_id_fk",
+ "tableFrom": "payload_preferences_rels",
+ "tableTo": "admins",
+ "columnsFrom": [
+ "admins_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ },
+ "payload_preferences_rels_users_id_users_id_fk": {
+ "name": "payload_preferences_rels_users_id_users_id_fk",
+ "tableFrom": "payload_preferences_rels",
+ "tableTo": "users",
+ "columnsFrom": [
+ "users_id"
+ ],
+ "columnsTo": [
+ "id"
+ ],
+ "onDelete": "cascade",
+ "onUpdate": "no action"
+ }
+ },
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ },
+ "payload_migrations": {
+ "name": "payload_migrations",
+ "schema": "",
+ "columns": {
+ "id": {
+ "name": "id",
+ "type": "serial",
+ "primaryKey": true,
+ "notNull": true
+ },
+ "name": {
+ "name": "name",
+ "type": "varchar",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "batch": {
+ "name": "batch",
+ "type": "numeric",
+ "primaryKey": false,
+ "notNull": false
+ },
+ "updated_at": {
+ "name": "updated_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ },
+ "created_at": {
+ "name": "created_at",
+ "type": "timestamp(3) with time zone",
+ "primaryKey": false,
+ "notNull": true,
+ "default": "now()"
+ }
+ },
+ "indexes": {
+ "created_at_idx": {
+ "name": "created_at_idx",
+ "columns": [
+ "created_at"
+ ],
+ "isUnique": false
+ }
+ },
+ "foreignKeys": {},
+ "compositePrimaryKeys": {},
+ "uniqueConstraints": {}
+ }
+ },
+ "enums": {
+ "_locales": {
+ "name": "_locales",
+ "values": {
+ "fr": "fr"
+ }
+ },
+ "enum_offers_kind": {
+ "name": "enum_offers_kind",
+ "values": {
+ "voucher": "voucher",
+ "code": "code"
+ }
+ },
+ "enum_coupons_status": {
+ "name": "enum_coupons_status",
+ "values": {
+ "available": "available",
+ "archived": "archived"
+ }
+ }
+ },
+ "schemas": {},
+ "_meta": {
+ "schemas": {},
+ "tables": {},
+ "columns": {}
+ }
+}
\ No newline at end of file
diff --git a/webapp/src/payload/migrations/20240126_145518.ts b/webapp/src/payload/migrations/20240126_145518.ts
new file mode 100644
index 00000000..c427f547
--- /dev/null
+++ b/webapp/src/payload/migrations/20240126_145518.ts
@@ -0,0 +1,16 @@
+import { MigrateUpArgs, MigrateDownArgs } from '@payloadcms/db-postgres'
+import { sql } from 'drizzle-orm'
+
+export async function up({ payload }: MigrateUpArgs): Promise {
+await payload.db.drizzle.execute(sql`
+
+DROP INDEX IF EXISTS "code_idx";`);
+
+};
+
+export async function down({ payload }: MigrateDownArgs): Promise {
+await payload.db.drizzle.execute(sql`
+
+CREATE UNIQUE INDEX IF NOT EXISTS "code_idx" ON "coupons" ("code");`);
+
+};
diff --git a/webapp/src/payload/payload-types.ts b/webapp/src/payload/payload-types.ts
index 6fe28f2a..91a7089f 100644
--- a/webapp/src/payload/payload-types.ts
+++ b/webapp/src/payload/payload-types.ts
@@ -14,6 +14,7 @@ export interface Config {
categories: Category;
partners: Partner;
offers: Offer;
+ coupons: Coupon;
'payload-preferences': PayloadPreference;
'payload-migrations': PayloadMigration;
};
@@ -60,39 +61,12 @@ export interface Media {
filesize?: number | null;
width?: number | null;
height?: number | null;
- sizes?: {
- thumbnail?: {
- url?: string | null;
- width?: number | null;
- height?: number | null;
- mimeType?: string | null;
- filesize?: number | null;
- filename?: string | null;
- };
- card?: {
- url?: string | null;
- width?: number | null;
- height?: number | null;
- mimeType?: string | null;
- filesize?: number | null;
- filename?: string | null;
- };
- tablet?: {
- url?: string | null;
- width?: number | null;
- height?: number | null;
- mimeType?: string | null;
- filesize?: number | null;
- filename?: string | null;
- };
- };
}
export interface Category {
id: number;
slug: string;
label: string;
icon: number | Media;
- color: string;
updatedAt: string;
createdAt: string;
}
@@ -100,6 +74,8 @@ export interface Partner {
id: number;
name: string;
description: string;
+ url: string;
+ color: string;
icon: number | Media;
updatedAt: string;
createdAt: string;
@@ -109,10 +85,20 @@ export interface Offer {
title: string;
partner: number | Partner;
category: number | Category;
+ validityTo: string;
kind: 'voucher' | 'code';
updatedAt: string;
createdAt: string;
}
+export interface Coupon {
+ id: number;
+ code: string;
+ status: 'available' | 'archived';
+ user?: (number | null) | User;
+ offer: number | Offer;
+ updatedAt: string;
+ createdAt: string;
+}
export interface PayloadPreference {
id: number;
user:
diff --git a/webapp/src/payload/payload.config.ts b/webapp/src/payload/payload.config.ts
index 4fac6afc..6b0bd5c0 100644
--- a/webapp/src/payload/payload.config.ts
+++ b/webapp/src/payload/payload.config.ts
@@ -12,6 +12,7 @@ import { Media } from "./collections/Media";
import { Categories } from "./collections/Categorie";
import { Partners } from "./collections/Partner";
import { Offers } from "./collections/Offer";
+import { Coupons } from "./collections/Coupon";
const adapter = s3Adapter({
config: {
@@ -27,11 +28,12 @@ const adapter = s3Adapter({
export default buildConfig({
db: postgresAdapter({
+ migrationDir: path.resolve(__dirname, "./migrations"),
pool: {
connectionString:
process.env.NODE_ENV !== "production"
? process.env.DATABASE_URL
- : `postgresql://${process.env.PGDATABASE}:${process.env.PGPASSWORD}@${process.env.PGHOST}:${process.env.PGPORT}/${process.env.PGDATABASE}?sslmode=disable`,
+ : `postgresql://${process.env.PGUSER}:${process.env.PGPASSWORD}@${process.env.PGHOST}:${process.env.PGPORT}/${process.env.PGDATABASE}?sslmode=disable`,
},
}),
plugins: [
@@ -51,7 +53,7 @@ export default buildConfig({
bundler: webpackBundler(),
user: "admins",
},
- collections: [Admins, Users, Media, Categories, Partners, Offers],
+ collections: [Admins, Users, Media, Categories, Partners, Offers, Coupons],
localization: {
locales: ["fr"],
defaultLocale: "fr",
diff --git a/webapp/src/payload/payloadClient.ts b/webapp/src/payload/payloadClient.ts
index f80a7f11..31b9afee 100644
--- a/webapp/src/payload/payloadClient.ts
+++ b/webapp/src/payload/payloadClient.ts
@@ -9,40 +9,40 @@ import config from "./payload.config";
* Source: https://github.com/vercel/next.js/blob/canary/examples/with-mongodb-mongoose/lib/dbConnect.js
*/
let cached: {
- client: Payload | null;
- promise: Promise | null;
+ client: Payload | null;
+ promise: Promise | null;
} = (global as any).payload;
if (!cached) {
- cached = (global as any).payload = { client: null, promise: null };
+ cached = (global as any).payload = { client: null, promise: null };
}
interface Args {
- seed?: boolean;
+ seed?: boolean;
}
export const getPayloadClient = async (args: Args): Promise => {
- if (cached.client) {
- return cached.client;
- }
-
- if (!cached.promise) {
- cached.promise = getPayload({
- // Make sure that your environment variables are filled out accordingly
- secret: process.env.PAYLOAD_SECRET as string,
- config: config,
- local: args?.seed ?? false,
- });
- }
-
- try {
- cached.client = await cached.promise;
- } catch (e) {
- cached.promise = null;
- throw e;
- }
-
- return cached.client;
+ if (cached.client) {
+ return cached.client;
+ }
+
+ if (!cached.promise) {
+ cached.promise = getPayload({
+ // Make sure that your environment variables are filled out accordingly
+ secret: process.env.PAYLOAD_SECRET as string,
+ config: config,
+ local: args?.seed ?? false,
+ });
+ }
+
+ try {
+ cached.client = await cached.promise;
+ } catch (e) {
+ cached.promise = null;
+ throw e;
+ }
+
+ return cached.client;
};
export default getPayloadClient;
diff --git a/webapp/src/payload/seed/categories.ts b/webapp/src/payload/seed/categories.ts
index 830ac4e0..97293a4d 100644
--- a/webapp/src/payload/seed/categories.ts
+++ b/webapp/src/payload/seed/categories.ts
@@ -5,27 +5,38 @@ export const categories = [
{
slug: "shop",
label: "Courses",
- color: "#FACBD1",
},
{
- slug: "care",
- label: "Soins",
- color: "#CDE0FF",
+ slug: "mobility",
+ label: "Mobilité",
},
{
- slug: "services",
- label: "Services",
- color: "#DBF0EB",
+ slug: "hobby",
+ label: "Loisirs",
},
{
- slug: "telephony",
- label: "Téléphonie",
- color: "#FEDF6B",
+ slug: "sport",
+ label: "Sport",
},
{
- slug: "mobility",
- label: "Mobilité",
- color: "#CACAFB",
+ slug: "hygiene",
+ label: "Hygiène",
+ },
+ {
+ slug: "equipment",
+ label: "Équipement",
+ },
+ {
+ slug: "hosting",
+ label: "Hébergement",
+ },
+ {
+ slug: "bank",
+ label: "Banque, mutuelle, assurance",
+ },
+ {
+ slug: "telephony",
+ label: "Téléphone, internet",
},
] as const;
@@ -35,9 +46,7 @@ export async function seedCategories(payload: Payload) {
collection: "media",
filePath: path.join(
__dirname,
- `../../../public/images/seeds/categories/${category.slug}.${
- category.slug === "mobility" ? "png" : "svg"
- }`
+ `../../../public/images/seeds/categories/${category.slug}.png`
),
data: {
alt: `${category.slug} icon`,
diff --git a/webapp/src/payload/seed/offers.ts b/webapp/src/payload/seed/offers.ts
index e5ee38c4..b3bd06f5 100644
--- a/webapp/src/payload/seed/offers.ts
+++ b/webapp/src/payload/seed/offers.ts
@@ -4,13 +4,19 @@ import { partners } from "./partners";
import { categories } from "./categories";
export async function seedOffers(payload: Payload) {
+ const currentDate = new Date();
+ const validityTo = new Date(
+ currentDate.setMonth(currentDate.getMonth() + 1)
+ ).toISOString();
+
const offers: Omit[] = [
{
title: "15% de réduction sur les produits alimentaire",
- partner: partners.findIndex((partner) => partner.name === "Leclerc") + 1,
+ partner: partners.findIndex((partner) => partner.name === "Cora") + 1,
category:
categories.findIndex((category) => category.slug === "shop") + 1,
kind: "voucher",
+ validityTo,
},
{
title: "10% de réduction sur plus de 50 produits alimentaire",
@@ -18,6 +24,7 @@ export async function seedOffers(payload: Payload) {
category:
categories.findIndex((category) => category.slug === "shop") + 1,
kind: "voucher",
+ validityTo,
},
{
title: "10% de réduction les produits alimentaire",
@@ -25,6 +32,7 @@ export async function seedOffers(payload: Payload) {
category:
categories.findIndex((category) => category.slug === "shop") + 1,
kind: "voucher",
+ validityTo,
},
{
title: "10% de réduction sur l’ensemble des billets en France et Europe",
@@ -32,6 +40,7 @@ export async function seedOffers(payload: Payload) {
category:
categories.findIndex((category) => category.slug === "mobility") + 1,
kind: "code",
+ validityTo,
},
];
diff --git a/webapp/src/payload/seed/partners.ts b/webapp/src/payload/seed/partners.ts
index 879605f0..24f012ba 100644
--- a/webapp/src/payload/seed/partners.ts
+++ b/webapp/src/payload/seed/partners.ts
@@ -3,20 +3,28 @@ import { type Payload } from "payload";
export const partners = [
{
- name: "Leclerc",
- description: "Description de Leclerc",
+ name: "Cora",
+ description: "Description de Cora",
+ color: "#283F93",
+ url: "https://www.cora.fr/",
},
{
name: "Lidl",
description: "Description de Lidl",
+ color: "#FFF000",
+ url: "https://www.lidl.fr/",
},
{
name: "Auchan",
description: "Description de Auchan",
+ color: "#E0001A",
+ url: "https://www.auchan.fr/",
},
{
name: "Flixbus",
description: "Description de Flixbus",
+ color: "#73D700",
+ url: "https://www.flixbus.fr/",
},
] as const;
diff --git a/webapp/src/providers/Auth.tsx b/webapp/src/providers/Auth.tsx
index da1e49b6..ec7eddd7 100644
--- a/webapp/src/providers/Auth.tsx
+++ b/webapp/src/providers/Auth.tsx
@@ -18,7 +18,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
useEffect(() => {
const fetchMe = async () => {
- const token = getCookie(process.env.NEXT_PUBLIC_JWT_NAME as string);
+ const token = getCookie(process.env.NEXT_PUBLIC_JWT_NAME ?? "cje-jwt");
if (!token) return;
const result = await fetch("/api/users/me", {
headers: {
@@ -29,8 +29,8 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
setUser(result.user);
} else {
setUser(null);
- deleteCookie(process.env.NEXT_PUBLIC_JWT_NAME as string);
- router.push("/login");
+ deleteCookie(process.env.NEXT_PUBLIC_JWT_NAME ?? "cje-jwt");
+ router.push("/");
}
};
diff --git a/webapp/src/server/api/root.ts b/webapp/src/server/api/root.ts
index 5b8e3b32..fca8bed7 100644
--- a/webapp/src/server/api/root.ts
+++ b/webapp/src/server/api/root.ts
@@ -3,6 +3,7 @@ import { createTRPCRouter } from "~/server/api/trpc";
import { userRouter } from "./routers/user";
import { categoryRouter } from "./routers/category";
import { offerRouter } from "./routers/offer";
+import { couponRouter } from "./routers/coupon";
/**
* This is the primary router for your server.
@@ -13,6 +14,7 @@ export const appRouter = createTRPCRouter({
user: userRouter,
category: categoryRouter,
offer: offerRouter,
+ coupon: couponRouter,
});
// export type definition of API
diff --git a/webapp/src/server/api/routers/category.ts b/webapp/src/server/api/routers/category.ts
index bd120f7f..8666fc6b 100644
--- a/webapp/src/server/api/routers/category.ts
+++ b/webapp/src/server/api/routers/category.ts
@@ -1,8 +1,10 @@
-import type { Category, Media } from "~/payload/payload-types";
-import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
-import { ZGetListParams } from "~/server/types";
+import { TRPCError } from '@trpc/server';
+import { z } from 'zod';
+import type { Category, Media } from '~/payload/payload-types';
+import { createTRPCRouter, protectedProcedure } from '~/server/api/trpc';
+import { ZGetListParams } from '~/server/types';
-interface CategoryIncluded extends Category {
+export interface CategoryIncluded extends Category {
icon: Media;
}
@@ -13,15 +15,39 @@ export const categoryRouter = createTRPCRouter({
const { perPage, page, sort } = input;
const categories = await ctx.payload.find({
- collection: "categories",
+ collection: 'categories',
limit: perPage,
page: page,
- sort,
+ sort
});
return {
data: categories.docs as CategoryIncluded[],
- metadata: { page, count: categories.docs.length },
+ metadata: { page, count: categories.docs.length }
};
}),
+
+ getBySlug: protectedProcedure
+ .input(z.object({ slug: z.string() }))
+ .query(async ({ ctx, input }) => {
+ const { slug } = input;
+
+ const category = await ctx.payload.find({
+ collection: 'categories',
+ where: {
+ slug: {
+ equals: slug
+ }
+ }
+ });
+
+ if (!category.docs.length) {
+ throw new TRPCError({
+ code: 'NOT_FOUND',
+ message: 'Category not found'
+ });
+ }
+
+ return { data: category.docs[0] as CategoryIncluded };
+ })
});
diff --git a/webapp/src/server/api/routers/coupon.ts b/webapp/src/server/api/routers/coupon.ts
new file mode 100644
index 00000000..e883d278
--- /dev/null
+++ b/webapp/src/server/api/routers/coupon.ts
@@ -0,0 +1,68 @@
+import { TRPCError } from '@trpc/server';
+import { z } from 'zod';
+import { Coupon, Media, Offer, Partner, User } from '~/payload/payload-types';
+import { createTRPCRouter, protectedProcedure } from '~/server/api/trpc';
+
+export interface CouponIncluded extends Coupon {
+ offer: Offer & { icon: Media; partner: Partner };
+ userRouter: User;
+}
+
+export const couponRouter = createTRPCRouter({
+ getOne: protectedProcedure
+ .input(z.object({ offer_id: z.number() }))
+ .query(async ({ ctx, input }) => {
+ const { offer_id } = input;
+
+ const coupons = await ctx.payload.find({
+ collection: 'coupons',
+ depth: 2,
+ where: {
+ and: [
+ { offer: { equals: offer_id } },
+ { status: { equals: 'available' } },
+ { user: { equals: ctx.session.id } }
+ ]
+ }
+ });
+
+ return { data: coupons.docs[0] as CouponIncluded };
+ }),
+
+ assignToUser: protectedProcedure
+ .input(z.object({ offer_id: z.number() }))
+ .mutation(async ({ ctx, input }) => {
+ const { offer_id } = input;
+
+ const coupons = await ctx.payload.find({
+ collection: 'coupons',
+ where: {
+ and: [
+ { offer: { equals: offer_id } },
+ { status: { equals: 'available' } }
+ ]
+ }
+ });
+
+ const couponsFiltered = coupons.docs.filter(
+ coupon => coupon.user === undefined || coupon.user === null
+ );
+
+ if (couponsFiltered.length === 0) {
+ throw new TRPCError({
+ code: 'NOT_FOUND',
+ message: 'No coupons available for this offer'
+ });
+ }
+
+ const couponData = couponsFiltered[0] as CouponIncluded;
+
+ const updatedCoupon = await ctx.payload.update({
+ collection: 'coupons',
+ id: couponData.id,
+ data: { user: ctx.session.id }
+ });
+
+ return { data: updatedCoupon };
+ })
+});
diff --git a/webapp/src/server/api/routers/offer.ts b/webapp/src/server/api/routers/offer.ts
index 602afb3f..0dac206c 100644
--- a/webapp/src/server/api/routers/offer.ts
+++ b/webapp/src/server/api/routers/offer.ts
@@ -1,28 +1,74 @@
+import { z } from "zod";
import { Category, Offer, Media, Partner } from "~/payload/payload-types";
import { createTRPCRouter, protectedProcedure } from "~/server/api/trpc";
import { ZGetListParams } from "~/server/types";
-interface OfferIncluded extends Offer {
+export interface OfferIncluded extends Offer {
partner: Partner & { icon: Media };
category: Category & { icon: Media };
}
export const offerRouter = createTRPCRouter({
getList: protectedProcedure
- .input(ZGetListParams)
+ .input(
+ ZGetListParams.merge(z.object({ categoryId: z.number().optional() }))
+ )
.query(async ({ ctx, input }) => {
- const { perPage, page, sort } = input;
+ const { perPage, page, sort, categoryId } = input;
const offers = await ctx.payload.find({
collection: "offers",
limit: perPage,
page: page,
+ where: categoryId
+ ? {
+ category: {
+ equals: categoryId,
+ },
+ }
+ : {},
sort,
});
+ const couponCountOfOffers = await ctx.payload.find({
+ collection: "coupons",
+ depth: 0,
+ where: {
+ offer: {
+ in: offers.docs.map((offer) => offer.id),
+ },
+ },
+ });
+
+ const offersFiltered = offers.docs.filter((offer) => {
+ const couponCount = couponCountOfOffers.docs.filter(
+ (coupon) =>
+ coupon.offer === offer.id &&
+ coupon.status === "available" &&
+ (coupon.user === undefined ||
+ coupon.user === null ||
+ coupon.user === ctx.session.id)
+ ).length;
+
+ if (couponCount > 0) return offer;
+ });
+
return {
- data: offers.docs as OfferIncluded[],
+ data: offersFiltered as OfferIncluded[],
metadata: { page, count: offers.docs.length },
};
}),
+
+ getById: protectedProcedure
+ .input(z.object({ id: z.number() }))
+ .query(async ({ ctx, input }) => {
+ const { id } = input;
+
+ const offer = await ctx.payload.findByID({
+ collection: "offers",
+ id,
+ });
+
+ return { data: offer as OfferIncluded };
+ }),
});
diff --git a/webapp/src/server/api/routers/user.ts b/webapp/src/server/api/routers/user.ts
index f55da709..79d5be15 100644
--- a/webapp/src/server/api/routers/user.ts
+++ b/webapp/src/server/api/routers/user.ts
@@ -1,11 +1,11 @@
-import { TRPCError } from "@trpc/server";
-import APIError from "payload/dist/errors/APIError";
-import { z } from "zod";
+import { TRPCError } from '@trpc/server';
+import APIError from 'payload/dist/errors/APIError';
+import { z } from 'zod';
import {
createTRPCRouter,
protectedProcedure,
- publicProcedure,
-} from "~/server/api/trpc";
+ publicProcedure
+} from '~/server/api/trpc';
export const userRouter = createTRPCRouter({
register: publicProcedure
@@ -14,34 +14,34 @@ export const userRouter = createTRPCRouter({
email: z.string().email(),
firstName: z.string(),
lastName: z.string(),
- password: z.string(),
+ password: z.string()
})
)
.mutation(async ({ ctx, input: userInput }) => {
try {
const newUser = await ctx.payload.create({
- collection: "users",
- data: userInput,
+ collection: 'users',
+ data: userInput
});
return { data: newUser };
} catch (error: unknown) {
if (error instanceof APIError) {
if (
- error.data[0].field === "email" &&
- error.data[0].message.includes("registered")
+ error.data[0].field === 'email' &&
+ error.data[0].message.includes('registered')
) {
throw new TRPCError({
- code: "CONFLICT",
- message: "Email already registered",
- cause: error,
+ code: 'CONFLICT',
+ message: 'Email already registered',
+ cause: error
});
}
}
throw new TRPCError({
- code: "BAD_REQUEST",
- message: "Unknown error",
- cause: error,
+ code: 'BAD_REQUEST',
+ message: 'Unknown error',
+ cause: error
});
}
}),
@@ -50,39 +50,33 @@ export const userRouter = createTRPCRouter({
.input(
z.object({
email: z.string().email(),
- password: z.string(),
+ password: z.string()
})
)
.mutation(async ({ ctx, input: userInput }) => {
try {
const user = await ctx.payload.login({
- collection: "users",
- data: userInput,
+ collection: 'users',
+ data: userInput
});
return { data: user };
} catch (error) {
- if (error && typeof error === "object" && "status" in error) {
+ if (error && typeof error === 'object' && 'status' in error) {
if (error.status === 401) {
throw new TRPCError({
- code: "UNAUTHORIZED",
- message: "Invalid email or password",
- cause: error,
+ code: 'UNAUTHORIZED',
+ message: 'Invalid email or password',
+ cause: error
});
}
}
throw new TRPCError({
- code: "BAD_REQUEST",
- message: "Unknown error",
- cause: error,
+ code: 'BAD_REQUEST',
+ message: 'Unknown error',
+ cause: error
});
}
- }),
-
- logout: protectedProcedure.mutation(async () => {
- await fetch("/api/users/logout");
-
- return { data: true };
- }),
+ })
});
diff --git a/webapp/src/server/api/trpc.ts b/webapp/src/server/api/trpc.ts
index ce03fab1..a07f7e04 100644
--- a/webapp/src/server/api/trpc.ts
+++ b/webapp/src/server/api/trpc.ts
@@ -57,7 +57,7 @@ export const createTRPCContext = async (_opts: CreateNextContextOptions) => {
});
const jwtCookie =
- _opts.req.cookies[process.env.NEXT_PUBLIC_JWT_NAME as string];
+ _opts.req.cookies[process.env.NEXT_PUBLIC_JWT_NAME ?? "cje-jwt"];
if (!jwtCookie) {
return {
diff --git a/webapp/src/styles/globals.css b/webapp/src/styles/globals.css
index ed316524..af3161ca 100644
--- a/webapp/src/styles/globals.css
+++ b/webapp/src/styles/globals.css
@@ -112,3 +112,9 @@ a {
color-scheme: dark;
}
}
+
+/* disable default tap color */
+
+* {
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0.05);
+}
diff --git a/webapp/src/utils/animations.ts b/webapp/src/utils/animations.ts
new file mode 100644
index 00000000..741a86bf
--- /dev/null
+++ b/webapp/src/utils/animations.ts
@@ -0,0 +1,84 @@
+import gsap, { Cubic } from 'gsap';
+
+export const couponAnimation = (isSuccess: boolean, couponExists: boolean) => {
+ if (isSuccess) {
+ gsap.to('#coupon-code-icon', {
+ backgroundColor: '#42B918',
+ color: 'white',
+ duration: 1
+ });
+
+ gsap.to('#coupon-code-icon-lock', {
+ display: 'none',
+ duration: 0,
+ delay: 0.5
+ });
+
+ gsap.to('#coupon-code-icon-unlock', {
+ display: 'block',
+ duration: 0,
+ delay: 0.5
+ });
+ }
+
+ gsap.to('#coupon-code-icon', {
+ opacity: couponExists ? 0 : 1,
+ duration: isSuccess ? 0.5 : 0,
+ delay: isSuccess ? 1.25 : 0
+ });
+
+ gsap.to('#coupon-code-text', {
+ filter: couponExists ? 'blur(0px)' : 'blur(4.5px)',
+ duration: isSuccess ? 1 : 0,
+ delay: isSuccess ? 1.75 : 0
+ });
+
+ if (isSuccess) {
+ gsap.fromTo(
+ '.coupon-info',
+ {
+ scaleY: 0,
+ opacity: 0,
+ transformOrigin: 'top'
+ },
+ {
+ scaleY: 1,
+ transformOrigin: 'top',
+ opacity: 1,
+ ease: Cubic.easeIn,
+ duration: 0.75,
+ delay: 1.5
+ }
+ );
+
+ gsap.fromTo(
+ '.btn-utils',
+ {
+ opacity: 0,
+ translateY: -35
+ },
+ {
+ opacity: 1,
+ translateY: 0,
+ duration: 1,
+ ease: Cubic.easeIn,
+ delay: 1.5
+ }
+ );
+
+ gsap.fromTo(
+ '.btn-conditions',
+ {
+ translateY: -35,
+ delay: 1
+ },
+ {
+ opacity: 1,
+ duration: 1,
+ translateY: 0,
+ ease: Cubic.easeIn,
+ delay: 1.5
+ }
+ );
+ }
+};
diff --git a/webapp/src/utils/chakra-theme.ts b/webapp/src/utils/chakra-theme.ts
index 4210e100..f7ccc8fd 100644
--- a/webapp/src/utils/chakra-theme.ts
+++ b/webapp/src/utils/chakra-theme.ts
@@ -1,5 +1,9 @@
/* theme.ts */
-import { extendTheme } from "@chakra-ui/react";
+import {
+ StyleFunctionProps,
+ extendTheme,
+ theme as defaultTheme,
+} from "@chakra-ui/react";
import localFont from "next/font/local";
export const Marianne = localFont({
@@ -37,18 +41,49 @@ export const Marianne = localFont({
],
});
+export const dottedPattern = (bgColor: string) => ({
+ _after: {
+ content: `""`,
+ position: "absolute",
+ bottom: -2, // Adjust this value as needed to align with your design
+ left: 0,
+ right: 0,
+ height: "40px", // This is the height of the pseudo-element
+ backgroundImage: `radial-gradient(circle, ${bgColor} 8px, rgba(0, 0, 0, 0) 8px)`, // The color should be the same as the border color
+ backgroundSize: "23px 17px", // Adjust the size of the dots
+ backgroundRepeat: "repeat-x",
+ backgroundPosition: "bottom",
+ },
+});
+
export const theme = extendTheme({
components: {
Button: {
sizes: {
lg: {
- px: "1.5rem",
- borderRadius: "6.25rem",
+ borderRadius: "2xl",
+ py: 8,
+ fontWeight: "medium",
+ },
+ sm: {
+ borderRadius: "lg",
+ py: 12,
+ fontWeight: "medium",
+ whiteSpace: "normal",
},
},
defaultProps: {
size: "lg",
- colorScheme: "primary",
+ colorScheme: "blackBtn",
+ },
+ variants: {
+ solid: (props: StyleFunctionProps) => ({
+ "@media(hover: none)": {
+ _hover: {
+ bg: defaultTheme.components.Button.variants?.solid(props).bg,
+ },
+ },
+ }),
},
},
},
@@ -65,7 +100,44 @@ export const theme = extendTheme({
"900": "#282a87",
"950": "#18184e",
},
- bgWhite: "#F7F7FA",
+ whiteBtn: {
+ "50": "#FFFFFF",
+ "100": "#FFFFFF",
+ "200": "#FFFFFF",
+ "300": "#FFFFFF",
+ "400": "#FFFFFF",
+ "500": "#FFFFFF",
+ "600": "#FFFFFF",
+ "700": "#FFFFFF",
+ "800": "#FFFFFF",
+ "900": "#FFFFFF",
+ },
+ blackBtn: {
+ "50": "#000000",
+ "100": "#000000",
+ "200": "#000000",
+ "300": "#000000",
+ "400": "#000000",
+ "500": "#000000",
+ "600": "#000000",
+ "700": "#000000",
+ "800": "#000000",
+ "900": "#000000",
+ },
+ "cje-gray": {
+ "50": "#f6f7f9",
+ "100": "#c5c7cb",
+ "200": "#cfd1d5",
+ "300": "#d9dbdf",
+ "400": "#e3e5e9",
+ "500": "#edeff3",
+ "600": "#f7f9fd",
+ "700": "#ffffff",
+ "800": "#ffffff",
+ "900": "#ffffff",
+ },
+ success: "#42B918",
+ bgWhite: "#F7F7F7",
disabled: "#9595B1",
},
fonts: {
diff --git a/webapp/src/utils/tools.ts b/webapp/src/utils/tools.ts
new file mode 100644
index 00000000..b28ea34f
--- /dev/null
+++ b/webapp/src/utils/tools.ts
@@ -0,0 +1,20 @@
+export const convertFrenchDateToEnglish = (
+ frenchDate: string
+): string | null => {
+ const match = frenchDate.match(/^(\d{2})\/(\d{2})\/(\d{2})$/);
+
+ if (match) {
+ const [, day, month, year] = match.map(Number);
+
+ if (year !== undefined && month !== undefined && day !== undefined) {
+ // Creating a Date object with a four-digit year
+ const englishFormattedDate = new Date(2000 + year, month - 1, day);
+
+ // Using toISOString to get the date in ISO format (YYYY-MM-DD)
+ return englishFormattedDate.toISOString().split("T")[0] || null;
+ }
+ }
+
+ // Return null if the input format is incorrect
+ return null;
+};
diff --git a/webapp/tsconfig.json b/webapp/tsconfig.json
index 27ec68b2..afc9a30d 100644
--- a/webapp/tsconfig.json
+++ b/webapp/tsconfig.json
@@ -1,6 +1,5 @@
{
"compilerOptions": {
- /* Base Options: */
"esModuleInterop": true,
"skipLibCheck": true,
"target": "es2022",
@@ -8,13 +7,9 @@
"resolveJsonModule": true,
"moduleDetection": "force",
"isolatedModules": true,
-
- /* Strictness */
"strict": true,
"noUncheckedIndexedAccess": true,
"checkJs": true,
-
- /* Bundled projects */
"lib": ["dom", "dom.iterable", "ES2022"],
"noEmit": true,
"module": "ESNext",
@@ -22,12 +17,8 @@
"jsx": "preserve",
"plugins": [{ "name": "next" }],
"incremental": true,
-
- /* Path Aliases */
"baseUrl": ".",
- "paths": {
- "~/*": ["./src/*"]
- }
+ "paths": { "~/*": ["./src/*"] }
},
"include": [
".eslintrc.cjs",
diff --git a/webapp/yarn.lock b/webapp/yarn.lock
index 3662b437..bcf5cb7a 100644
--- a/webapp/yarn.lock
+++ b/webapp/yarn.lock
@@ -2318,6 +2318,18 @@ __metadata:
languageName: node
linkType: hard
+"@chakra-ui/icons@npm:^2.1.1":
+ version: 2.1.1
+ resolution: "@chakra-ui/icons@npm:2.1.1"
+ dependencies:
+ "@chakra-ui/icon": "npm:3.2.0"
+ peerDependencies:
+ "@chakra-ui/system": ">=2.0.0"
+ react: ">=18"
+ checksum: 36c94df62216f7445e49dfec98363f4c836e154ba118e6c446e774cade6f9e0e04c33a62fbe2ff9de26eb87f6a3ee805f8c7fd2ddc82c8ef2744994443a83b33
+ languageName: node
+ linkType: hard
+
"@chakra-ui/image@npm:2.1.0":
version: 2.1.0
resolution: "@chakra-ui/image@npm:2.1.0"
@@ -3228,6 +3240,59 @@ __metadata:
languageName: node
linkType: hard
+"@cloudflare/kv-asset-handler@npm:^0.2.0":
+ version: 0.2.0
+ resolution: "@cloudflare/kv-asset-handler@npm:0.2.0"
+ dependencies:
+ mime: "npm:^3.0.0"
+ checksum: ec9816bb2901edff26e932566e77acff56c0a63927d78be6f05e44977209f0632103a802ba1498a2592bfc34c1e1502edba3644e8ff21ca10b201783ac5ff883
+ languageName: node
+ linkType: hard
+
+"@cloudflare/workerd-darwin-64@npm:1.20231218.0":
+ version: 1.20231218.0
+ resolution: "@cloudflare/workerd-darwin-64@npm:1.20231218.0"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@cloudflare/workerd-darwin-arm64@npm:1.20231218.0":
+ version: 1.20231218.0
+ resolution: "@cloudflare/workerd-darwin-arm64@npm:1.20231218.0"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@cloudflare/workerd-linux-64@npm:1.20231218.0":
+ version: 1.20231218.0
+ resolution: "@cloudflare/workerd-linux-64@npm:1.20231218.0"
+ conditions: os=linux & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@cloudflare/workerd-linux-arm64@npm:1.20231218.0":
+ version: 1.20231218.0
+ resolution: "@cloudflare/workerd-linux-arm64@npm:1.20231218.0"
+ conditions: os=linux & cpu=arm64
+ languageName: node
+ linkType: hard
+
+"@cloudflare/workerd-windows-64@npm:1.20231218.0":
+ version: 1.20231218.0
+ resolution: "@cloudflare/workerd-windows-64@npm:1.20231218.0"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
+"@cspotcode/source-map-support@npm:0.8.1":
+ version: 0.8.1
+ resolution: "@cspotcode/source-map-support@npm:0.8.1"
+ dependencies:
+ "@jridgewell/trace-mapping": "npm:0.3.9"
+ checksum: 05c5368c13b662ee4c122c7bfbe5dc0b613416672a829f3e78bc49a357a197e0218d6e74e7c66cfcd04e15a179acab080bd3c69658c9fbefd0e1ccd950a07fc6
+ languageName: node
+ linkType: hard
+
"@csstools/cascade-layer-name-parser@npm:^1.0.5, @csstools/cascade-layer-name-parser@npm:^1.0.7":
version: 1.0.7
resolution: "@csstools/cascade-layer-name-parser@npm:1.0.7"
@@ -3670,10 +3735,10 @@ __metadata:
languageName: node
linkType: hard
-"@drizzle-team/studio@npm:^0.0.5":
- version: 0.0.5
- resolution: "@drizzle-team/studio@npm:0.0.5"
- checksum: f6508128ba53baab231891ebe479f1828d120137a5aa07c5b599bfd2cf313eaec0c1cfa017fd6d88eb1652a1436353db07116c23bf15174f3ae829841d060b6d
+"@drizzle-team/studio@npm:^0.0.27":
+ version: 0.0.27
+ resolution: "@drizzle-team/studio@npm:0.0.27"
+ checksum: 6af2e00672c4842566ec9fcca7feac355b03d6670c09030bac42adebcc45f97e99aaf80d3f8fad63ee5aa6e7fb85354e3eb83eb295965e63f2a2bc8a3f5562cd
languageName: node
linkType: hard
@@ -3900,6 +3965,27 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild-plugins/node-globals-polyfill@npm:^0.2.3":
+ version: 0.2.3
+ resolution: "@esbuild-plugins/node-globals-polyfill@npm:0.2.3"
+ peerDependencies:
+ esbuild: "*"
+ checksum: da3591b3943076a8d4a78320c176f37e5a5802512e2c3a792d4dfe495c051e097668dc56513160147b43e86987078559490164905ef41d1326ac0a9e7a6498ac
+ languageName: node
+ linkType: hard
+
+"@esbuild-plugins/node-modules-polyfill@npm:^0.2.2":
+ version: 0.2.2
+ resolution: "@esbuild-plugins/node-modules-polyfill@npm:0.2.2"
+ dependencies:
+ escape-string-regexp: "npm:^4.0.0"
+ rollup-plugin-node-polyfills: "npm:^0.2.1"
+ peerDependencies:
+ esbuild: "*"
+ checksum: 8573eb409d19769ea6a2f621d8d7e344d84a9f19d03f37f4ace053e23dab8eeea08feea871c1704a2d39c0859adadfba808b59a50de4d227cb3879dbd90e7f52
+ languageName: node
+ linkType: hard
+
"@esbuild/aix-ppc64@npm:0.19.11":
version: 0.19.11
resolution: "@esbuild/aix-ppc64@npm:0.19.11"
@@ -3907,6 +3993,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/android-arm64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/android-arm64@npm:0.17.19"
+ conditions: os=android & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/android-arm64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/android-arm64@npm:0.18.20"
@@ -3921,6 +4014,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/android-arm@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/android-arm@npm:0.17.19"
+ conditions: os=android & cpu=arm
+ languageName: node
+ linkType: hard
+
"@esbuild/android-arm@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/android-arm@npm:0.18.20"
@@ -3935,6 +4035,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/android-x64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/android-x64@npm:0.17.19"
+ conditions: os=android & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/android-x64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/android-x64@npm:0.18.20"
@@ -3949,6 +4056,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/darwin-arm64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/darwin-arm64@npm:0.17.19"
+ conditions: os=darwin & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/darwin-arm64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/darwin-arm64@npm:0.18.20"
@@ -3963,6 +4077,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/darwin-x64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/darwin-x64@npm:0.17.19"
+ conditions: os=darwin & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/darwin-x64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/darwin-x64@npm:0.18.20"
@@ -3977,6 +4098,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/freebsd-arm64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/freebsd-arm64@npm:0.17.19"
+ conditions: os=freebsd & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/freebsd-arm64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/freebsd-arm64@npm:0.18.20"
@@ -3991,6 +4119,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/freebsd-x64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/freebsd-x64@npm:0.17.19"
+ conditions: os=freebsd & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/freebsd-x64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/freebsd-x64@npm:0.18.20"
@@ -4005,6 +4140,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-arm64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/linux-arm64@npm:0.17.19"
+ conditions: os=linux & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-arm64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/linux-arm64@npm:0.18.20"
@@ -4019,6 +4161,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-arm@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/linux-arm@npm:0.17.19"
+ conditions: os=linux & cpu=arm
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-arm@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/linux-arm@npm:0.18.20"
@@ -4033,6 +4182,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-ia32@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/linux-ia32@npm:0.17.19"
+ conditions: os=linux & cpu=ia32
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-ia32@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/linux-ia32@npm:0.18.20"
@@ -4047,6 +4203,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-loong64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/linux-loong64@npm:0.17.19"
+ conditions: os=linux & cpu=loong64
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-loong64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/linux-loong64@npm:0.18.20"
@@ -4061,6 +4224,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-mips64el@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/linux-mips64el@npm:0.17.19"
+ conditions: os=linux & cpu=mips64el
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-mips64el@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/linux-mips64el@npm:0.18.20"
@@ -4075,6 +4245,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-ppc64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/linux-ppc64@npm:0.17.19"
+ conditions: os=linux & cpu=ppc64
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-ppc64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/linux-ppc64@npm:0.18.20"
@@ -4089,6 +4266,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-riscv64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/linux-riscv64@npm:0.17.19"
+ conditions: os=linux & cpu=riscv64
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-riscv64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/linux-riscv64@npm:0.18.20"
@@ -4103,6 +4287,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-s390x@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/linux-s390x@npm:0.17.19"
+ conditions: os=linux & cpu=s390x
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-s390x@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/linux-s390x@npm:0.18.20"
@@ -4117,6 +4308,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/linux-x64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/linux-x64@npm:0.17.19"
+ conditions: os=linux & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/linux-x64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/linux-x64@npm:0.18.20"
@@ -4131,6 +4329,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/netbsd-x64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/netbsd-x64@npm:0.17.19"
+ conditions: os=netbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/netbsd-x64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/netbsd-x64@npm:0.18.20"
@@ -4145,6 +4350,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/openbsd-x64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/openbsd-x64@npm:0.17.19"
+ conditions: os=openbsd & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/openbsd-x64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/openbsd-x64@npm:0.18.20"
@@ -4159,6 +4371,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/sunos-x64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/sunos-x64@npm:0.17.19"
+ conditions: os=sunos & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/sunos-x64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/sunos-x64@npm:0.18.20"
@@ -4173,6 +4392,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/win32-arm64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/win32-arm64@npm:0.17.19"
+ conditions: os=win32 & cpu=arm64
+ languageName: node
+ linkType: hard
+
"@esbuild/win32-arm64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/win32-arm64@npm:0.18.20"
@@ -4187,6 +4413,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/win32-ia32@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/win32-ia32@npm:0.17.19"
+ conditions: os=win32 & cpu=ia32
+ languageName: node
+ linkType: hard
+
"@esbuild/win32-ia32@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/win32-ia32@npm:0.18.20"
@@ -4201,6 +4434,13 @@ __metadata:
languageName: node
linkType: hard
+"@esbuild/win32-x64@npm:0.17.19":
+ version: 0.17.19
+ resolution: "@esbuild/win32-x64@npm:0.17.19"
+ conditions: os=win32 & cpu=x64
+ languageName: node
+ linkType: hard
+
"@esbuild/win32-x64@npm:0.18.20":
version: 0.18.20
resolution: "@esbuild/win32-x64@npm:0.18.20"
@@ -4250,6 +4490,13 @@ __metadata:
languageName: node
linkType: hard
+"@fastify/busboy@npm:^2.0.0":
+ version: 2.1.0
+ resolution: "@fastify/busboy@npm:2.1.0"
+ checksum: 7bb641080aac7cf01d88749ad331af10ba9ec3713ec07cabbe833908c75df21bd56249bb6173bdec07f5a41896b21e3689316f86684c06635da45f91ff4565a2
+ languageName: node
+ linkType: hard
+
"@floating-ui/core@npm:^1.5.3":
version: 1.5.3
resolution: "@floating-ui/core@npm:1.5.3"
@@ -4276,6 +4523,16 @@ __metadata:
languageName: node
linkType: hard
+"@gsap/react@npm:^2.1.0":
+ version: 2.1.0
+ resolution: "@gsap/react@npm:2.1.0"
+ dependencies:
+ gsap: "npm:^3.12.4"
+ react: "npm:>=16"
+ checksum: 00ec2d2e312aae8ba56d323e373b70255e67b3825490c92087a18b02405711b31cfe7569e8c9eaf342b5b5c89e6716c6e16e1825ff751aa834c3ce9134f95b73
+ languageName: node
+ linkType: hard
+
"@hapi/hoek@npm:^9.0.0":
version: 9.3.0
resolution: "@hapi/hoek@npm:9.3.0"
@@ -4531,7 +4788,7 @@ __metadata:
languageName: node
linkType: hard
-"@jridgewell/resolve-uri@npm:^3.1.0":
+"@jridgewell/resolve-uri@npm:^3.0.3, @jridgewell/resolve-uri@npm:^3.1.0":
version: 3.1.1
resolution: "@jridgewell/resolve-uri@npm:3.1.1"
checksum: 0dbc9e29bc640bbbdc5b9876d2859c69042bfcf1423c1e6421bcca53e826660bff4e41c7d4bcb8dbea696404231a6f902f76ba41835d049e20f2dd6cffb713bf
@@ -4562,6 +4819,16 @@ __metadata:
languageName: node
linkType: hard
+"@jridgewell/trace-mapping@npm:0.3.9":
+ version: 0.3.9
+ resolution: "@jridgewell/trace-mapping@npm:0.3.9"
+ dependencies:
+ "@jridgewell/resolve-uri": "npm:^3.0.3"
+ "@jridgewell/sourcemap-codec": "npm:^1.4.10"
+ checksum: fa425b606d7c7ee5bfa6a31a7b050dd5814b4082f318e0e4190f991902181b4330f43f4805db1dd4f2433fd0ed9cc7a7b9c2683f1deeab1df1b0a98b1e24055b
+ languageName: node
+ linkType: hard
+
"@jridgewell/trace-mapping@npm:^0.3.17, @jridgewell/trace-mapping@npm:^0.3.18, @jridgewell/trace-mapping@npm:^0.3.20, @jridgewell/trace-mapping@npm:^0.3.9":
version: 0.3.20
resolution: "@jridgewell/trace-mapping@npm:0.3.20"
@@ -4863,21 +5130,21 @@ __metadata:
languageName: node
linkType: hard
-"@payloadcms/db-postgres@npm:^0.3.0":
- version: 0.3.0
- resolution: "@payloadcms/db-postgres@npm:0.3.0"
+"@payloadcms/db-postgres@npm:^0.4.0":
+ version: 0.4.0
+ resolution: "@payloadcms/db-postgres@npm:0.4.0"
dependencies:
"@libsql/client": "npm:^0.3.1"
console-table-printer: "npm:2.11.2"
- drizzle-kit: "npm:0.19.13-e99bac1"
- drizzle-orm: "npm:0.28.5"
+ drizzle-kit: "npm:0.20.5-608ae62"
+ drizzle-orm: "npm:0.29.3"
pg: "npm:8.11.3"
prompts: "npm:2.4.2"
to-snake-case: "npm:1.0.0"
uuid: "npm:9.0.0"
peerDependencies:
payload: ^2.0.0
- checksum: 12fb0538918170a9b6993e861dcd4a2b6cb1a3af453799b0ada6014597c8ada3ed066b50f8b2e537fcdf3cb0da903dbede37b4e533583e2c494c6f12053a857e
+ checksum: f9eb8a9a78b881a65b494d391e0e20a6b73674d335929f5b36f1cf45cd68209582172e061a5bd19dd7b683266e06ec4496a197cbe70408cd2ab6119ac4f9b079
languageName: node
linkType: hard
@@ -6120,6 +6387,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/node-forge@npm:^1.3.0":
+ version: 1.3.11
+ resolution: "@types/node-forge@npm:1.3.11"
+ dependencies:
+ "@types/node": "npm:*"
+ checksum: 3d7d23ca0ba38ac0cf74028393bd70f31169ab9aba43f21deb787840170d307d662644bac07287495effe2812ddd7ac8a14dbd43f16c2936bbb06312e96fc3b9
+ languageName: node
+ linkType: hard
+
"@types/node@npm:*, @types/node@npm:^20":
version: 20.11.0
resolution: "@types/node@npm:20.11.0"
@@ -6136,6 +6412,15 @@ __metadata:
languageName: node
linkType: hard
+"@types/papaparse@npm:^5":
+ version: 5.3.14
+ resolution: "@types/papaparse@npm:5.3.14"
+ dependencies:
+ "@types/node": "npm:*"
+ checksum: feb4d215903b67442feaa9836a6a5771e78dc6a9da24781e399c6f891622fa82245cd783ab2613c5be43e4a2d6a94da52325538e4485af258166864576ecd0d8
+ languageName: node
+ linkType: hard
+
"@types/parse-json@npm:^4.0.0":
version: 4.0.2
resolution: "@types/parse-json@npm:4.0.2"
@@ -6490,14 +6775,14 @@ __metadata:
languageName: node
linkType: hard
-"acorn-walk@npm:^8.0.0":
+"acorn-walk@npm:^8.0.0, acorn-walk@npm:^8.2.0":
version: 8.3.2
resolution: "acorn-walk@npm:8.3.2"
checksum: 7e2a8dad5480df7f872569b9dccff2f3da7e65f5353686b1d6032ab9f4ddf6e3a2cb83a9b52cf50b1497fd522154dda92f0abf7153290cc79cd14721ff121e52
languageName: node
linkType: hard
-"acorn@npm:^8.0.4, acorn@npm:^8.7.1, acorn@npm:^8.8.2":
+"acorn@npm:^8.0.4, acorn@npm:^8.7.1, acorn@npm:^8.8.0, acorn@npm:^8.8.2":
version: 8.11.3
resolution: "acorn@npm:8.11.3"
bin:
@@ -6712,6 +6997,15 @@ __metadata:
languageName: node
linkType: hard
+"as-table@npm:^1.0.36":
+ version: 1.0.55
+ resolution: "as-table@npm:1.0.55"
+ dependencies:
+ printable-characters: "npm:^1.0.42"
+ checksum: 8c5693a84621fe53c62fcad6b779dc55c5caf4d43b8e67077964baea4a337769ef53f590d7395c806805b4ef1a391b614ba9acdee19b2ca4309ddedaf13894e6
+ languageName: node
+ linkType: hard
+
"async@npm:^3.2.3":
version: 3.2.5
resolution: "async@npm:3.2.5"
@@ -6891,6 +7185,13 @@ __metadata:
languageName: node
linkType: hard
+"blake3-wasm@npm:^2.1.5":
+ version: 2.1.5
+ resolution: "blake3-wasm@npm:2.1.5"
+ checksum: 5dc729d8e3a9d1d7ab016b36cdda264a327ada0239716df48435163e11d2bf6df25d6e421655a1f52649098ae49555268a654729b7d02768f77c571ab37ef814
+ languageName: node
+ linkType: hard
+
"body-parser@npm:1.20.1":
version: 1.20.1
resolution: "body-parser@npm:1.20.1"
@@ -7170,6 +7471,16 @@ __metadata:
languageName: node
linkType: hard
+"capnp-ts@npm:^0.7.0":
+ version: 0.7.0
+ resolution: "capnp-ts@npm:0.7.0"
+ dependencies:
+ debug: "npm:^4.3.1"
+ tslib: "npm:^2.2.0"
+ checksum: 83d559c3d59126ee39295973bf2e9228cd4b559c81bfc938268c63deba4020f0df6ce2f2d1e2b7d7e4421de21f4854424b774ab9ac4d9a66d1c57d2fef7da870
+ languageName: node
+ linkType: hard
+
"chalk@npm:^2.4.2":
version: 2.4.2
resolution: "chalk@npm:2.4.2"
@@ -7205,7 +7516,7 @@ __metadata:
languageName: node
linkType: hard
-"chokidar@npm:>=3.0.0 <4.0.0":
+"chokidar@npm:>=3.0.0 <4.0.0, chokidar@npm:^3.5.3":
version: 3.5.3
resolution: "chokidar@npm:3.5.3"
dependencies:
@@ -7579,7 +7890,7 @@ __metadata:
languageName: node
linkType: hard
-"cookie@npm:0.5.0":
+"cookie@npm:0.5.0, cookie@npm:^0.5.0":
version: 0.5.0
resolution: "cookie@npm:0.5.0"
checksum: c01ca3ef8d7b8187bae434434582288681273b5a9ed27521d4d7f9f7928fe0c920df0decd9f9d3bbd2d14ac432b8c8cf42b98b3bdd5bfe0e6edddeebebe8b61d
@@ -7945,6 +8256,13 @@ __metadata:
languageName: node
linkType: hard
+"data-uri-to-buffer@npm:^2.0.0":
+ version: 2.0.2
+ resolution: "data-uri-to-buffer@npm:2.0.2"
+ checksum: 341b6191ed65fa453e97a6d44db06082121ebc2ef3e6e096dfb6a1ebbc75e8be39d4199a5b4dba0f0efc43f2a3b2bcc276d85cf1407eba880eb09ebf17c3c31e
+ languageName: node
+ linkType: hard
+
"data-uri-to-buffer@npm:^4.0.0":
version: 4.0.1
resolution: "data-uri-to-buffer@npm:4.0.1"
@@ -8313,11 +8631,11 @@ __metadata:
languageName: node
linkType: hard
-"drizzle-kit@npm:0.19.13-e99bac1":
- version: 0.19.13-e99bac1
- resolution: "drizzle-kit@npm:0.19.13-e99bac1"
+"drizzle-kit@npm:0.20.5-608ae62":
+ version: 0.20.5-608ae62
+ resolution: "drizzle-kit@npm:0.20.5-608ae62"
dependencies:
- "@drizzle-team/studio": "npm:^0.0.5"
+ "@drizzle-team/studio": "npm:^0.0.27"
"@esbuild-kit/esm-loader": "npm:^2.5.5"
camelcase: "npm:^7.0.1"
chalk: "npm:^5.2.0"
@@ -8328,16 +8646,17 @@ __metadata:
hanji: "npm:^0.0.5"
json-diff: "npm:0.9.0"
minimatch: "npm:^7.4.3"
+ wrangler: "npm:^3.7.0"
zod: "npm:^3.20.2"
bin:
- drizzle-kit: index.cjs
- checksum: 7df9775011305d090b0a3ec606cc44b9ba94c7884fb2d25f4acbaaf5aaa9ca92ed750071725714d5d4670ea16183e0c263a731d550f236551272b5a656a6a78f
+ drizzle-kit: bin.cjs
+ checksum: e1943056cc1bd6c09215b3cd5ad3f78a63604c964960cc67a018ceffc71dfd43a7dd4e9f6a5b8a34ef3ad5053862f9e516f47f0a8bf6fb365fbde9c295ce0836
languageName: node
linkType: hard
-"drizzle-orm@npm:0.28.5":
- version: 0.28.5
- resolution: "drizzle-orm@npm:0.28.5"
+"drizzle-orm@npm:0.29.3":
+ version: 0.29.3
+ resolution: "drizzle-orm@npm:0.29.3"
peerDependencies:
"@aws-sdk/client-rds-data": ">=3"
"@cloudflare/workers-types": ">=3"
@@ -8347,15 +8666,18 @@ __metadata:
"@planetscale/database": ">=1"
"@types/better-sqlite3": "*"
"@types/pg": "*"
+ "@types/react": ">=18"
"@types/sql.js": "*"
"@vercel/postgres": "*"
better-sqlite3: ">=7"
bun-types: "*"
+ expo-sqlite: ">=13.2.0"
knex: "*"
kysely: "*"
mysql2: ">=2"
pg: ">=8"
postgres: ">=3"
+ react: ">=18"
sql.js: ">=1"
sqlite3: ">=5"
peerDependenciesMeta:
@@ -8375,6 +8697,8 @@ __metadata:
optional: true
"@types/pg":
optional: true
+ "@types/react":
+ optional: true
"@types/sql.js":
optional: true
"@vercel/postgres":
@@ -8383,6 +8707,8 @@ __metadata:
optional: true
bun-types:
optional: true
+ expo-sqlite:
+ optional: true
knex:
optional: true
kysely:
@@ -8393,11 +8719,13 @@ __metadata:
optional: true
postgres:
optional: true
+ react:
+ optional: true
sql.js:
optional: true
sqlite3:
optional: true
- checksum: e62deb7caa8ca9c71824ab10ab06b3212bb5205561c3474504298554fee16d5a76c6731ae2e0f3955f150eb839bdd78a5750e1f0fe40d1c3ffcdc04140ed4519
+ checksum: a5a53e4599981f256e10bd0e6e4724f14ffe7c9f6bef963c5cc9d00c8379c2367324ae0c67abc52a319704fedba796a5583dac3d36fac0de19585f87844d3611
languageName: node
linkType: hard
@@ -8723,6 +9051,83 @@ __metadata:
languageName: node
linkType: hard
+"esbuild@npm:0.17.19":
+ version: 0.17.19
+ resolution: "esbuild@npm:0.17.19"
+ dependencies:
+ "@esbuild/android-arm": "npm:0.17.19"
+ "@esbuild/android-arm64": "npm:0.17.19"
+ "@esbuild/android-x64": "npm:0.17.19"
+ "@esbuild/darwin-arm64": "npm:0.17.19"
+ "@esbuild/darwin-x64": "npm:0.17.19"
+ "@esbuild/freebsd-arm64": "npm:0.17.19"
+ "@esbuild/freebsd-x64": "npm:0.17.19"
+ "@esbuild/linux-arm": "npm:0.17.19"
+ "@esbuild/linux-arm64": "npm:0.17.19"
+ "@esbuild/linux-ia32": "npm:0.17.19"
+ "@esbuild/linux-loong64": "npm:0.17.19"
+ "@esbuild/linux-mips64el": "npm:0.17.19"
+ "@esbuild/linux-ppc64": "npm:0.17.19"
+ "@esbuild/linux-riscv64": "npm:0.17.19"
+ "@esbuild/linux-s390x": "npm:0.17.19"
+ "@esbuild/linux-x64": "npm:0.17.19"
+ "@esbuild/netbsd-x64": "npm:0.17.19"
+ "@esbuild/openbsd-x64": "npm:0.17.19"
+ "@esbuild/sunos-x64": "npm:0.17.19"
+ "@esbuild/win32-arm64": "npm:0.17.19"
+ "@esbuild/win32-ia32": "npm:0.17.19"
+ "@esbuild/win32-x64": "npm:0.17.19"
+ dependenciesMeta:
+ "@esbuild/android-arm":
+ optional: true
+ "@esbuild/android-arm64":
+ optional: true
+ "@esbuild/android-x64":
+ optional: true
+ "@esbuild/darwin-arm64":
+ optional: true
+ "@esbuild/darwin-x64":
+ optional: true
+ "@esbuild/freebsd-arm64":
+ optional: true
+ "@esbuild/freebsd-x64":
+ optional: true
+ "@esbuild/linux-arm":
+ optional: true
+ "@esbuild/linux-arm64":
+ optional: true
+ "@esbuild/linux-ia32":
+ optional: true
+ "@esbuild/linux-loong64":
+ optional: true
+ "@esbuild/linux-mips64el":
+ optional: true
+ "@esbuild/linux-ppc64":
+ optional: true
+ "@esbuild/linux-riscv64":
+ optional: true
+ "@esbuild/linux-s390x":
+ optional: true
+ "@esbuild/linux-x64":
+ optional: true
+ "@esbuild/netbsd-x64":
+ optional: true
+ "@esbuild/openbsd-x64":
+ optional: true
+ "@esbuild/sunos-x64":
+ optional: true
+ "@esbuild/win32-arm64":
+ optional: true
+ "@esbuild/win32-ia32":
+ optional: true
+ "@esbuild/win32-x64":
+ optional: true
+ bin:
+ esbuild: bin/esbuild
+ checksum: c7ac14bfaaebe4745d5d18347b4f6854fd1140acb9389e88dbfa5c20d4e2122451d9647d5498920470a880a605d6e5502b5c2102da6c282b01f129ddd49d2874
+ languageName: node
+ linkType: hard
+
"esbuild@npm:^0.18.6, esbuild@npm:~0.18.20":
version: 0.18.20
resolution: "esbuild@npm:0.18.20"
@@ -8941,6 +9346,13 @@ __metadata:
languageName: node
linkType: hard
+"estree-walker@npm:^0.6.1":
+ version: 0.6.1
+ resolution: "estree-walker@npm:0.6.1"
+ checksum: 6dabc855faa04a1ffb17b6a9121b6008ba75ab5a163ad9dc3d7fca05cfda374c5f5e91418d783496620ca75e99a73c40874d8b75f23b4117508cc8bde78e7b41
+ languageName: node
+ linkType: hard
+
"estree-walker@npm:^1.0.1":
version: 1.0.1
resolution: "estree-walker@npm:1.0.1"
@@ -8986,6 +9398,13 @@ __metadata:
languageName: node
linkType: hard
+"exit-hook@npm:^2.2.1":
+ version: 2.2.1
+ resolution: "exit-hook@npm:2.2.1"
+ checksum: 0803726d1b60aade6afd10c73e5a7e1bf256ac9bee78362a88e91a4f735e8c67899f2853ddc613072c05af07bbb067a9978a740e614db1aeef167d50c6dc5c09
+ languageName: node
+ linkType: hard
+
"expand-template@npm:^2.0.3":
version: 2.0.3
resolution: "expand-template@npm:2.0.3"
@@ -9545,6 +9964,16 @@ __metadata:
languageName: node
linkType: hard
+"get-source@npm:^2.0.12":
+ version: 2.0.12
+ resolution: "get-source@npm:2.0.12"
+ dependencies:
+ data-uri-to-buffer: "npm:^2.0.0"
+ source-map: "npm:^0.6.1"
+ checksum: b1db46d28902344fd9407e1f0ed0b8f3a85cb4650f85ba8cee9c0b422fc75118172f12f735706e2c6e034617b13a2fbc5266e7fab617ecb184f0cee074b9dd3e
+ languageName: node
+ linkType: hard
+
"get-stdin@npm:^8.0.0":
version: 8.0.0
resolution: "get-stdin@npm:8.0.0"
@@ -9792,6 +10221,13 @@ __metadata:
languageName: node
linkType: hard
+"gsap@npm:^3.12.4, gsap@npm:^3.12.5":
+ version: 3.12.5
+ resolution: "gsap@npm:3.12.5"
+ checksum: cb38e89bd577fc18c9cf77e4aeb83617603b1e0fa768fe8ca1acd836fd852936722e186a88c9cf6ece42e53407edd45324be2bfe35a41f424c5f2c2b33fd1a98
+ languageName: node
+ linkType: hard
+
"gzip-size@npm:^6.0.0":
version: 6.0.0
resolution: "gzip-size@npm:6.0.0"
@@ -11266,7 +11702,7 @@ __metadata:
languageName: node
linkType: hard
-"magic-string@npm:^0.25.0, magic-string@npm:^0.25.7":
+"magic-string@npm:^0.25.0, magic-string@npm:^0.25.3, magic-string@npm:^0.25.7":
version: 0.25.9
resolution: "magic-string@npm:0.25.9"
dependencies:
@@ -11447,6 +11883,15 @@ __metadata:
languageName: node
linkType: hard
+"mime@npm:^3.0.0":
+ version: 3.0.0
+ resolution: "mime@npm:3.0.0"
+ bin:
+ mime: cli.js
+ checksum: 402e792a8df1b2cc41cb77f0dcc46472b7944b7ec29cb5bbcd398624b6b97096728f1239766d3fdeb20551dd8d94738344c195a6ea10c4f906eb0356323b0531
+ languageName: node
+ linkType: hard
+
"mimic-fn@npm:^2.1.0":
version: 2.1.0
resolution: "mimic-fn@npm:2.1.0"
@@ -11481,6 +11926,28 @@ __metadata:
languageName: node
linkType: hard
+"miniflare@npm:3.20231218.3":
+ version: 3.20231218.3
+ resolution: "miniflare@npm:3.20231218.3"
+ dependencies:
+ "@cspotcode/source-map-support": "npm:0.8.1"
+ acorn: "npm:^8.8.0"
+ acorn-walk: "npm:^8.2.0"
+ capnp-ts: "npm:^0.7.0"
+ exit-hook: "npm:^2.2.1"
+ glob-to-regexp: "npm:^0.4.1"
+ stoppable: "npm:^1.1.0"
+ undici: "npm:^5.28.2"
+ workerd: "npm:1.20231218.0"
+ ws: "npm:^8.11.0"
+ youch: "npm:^3.2.2"
+ zod: "npm:^3.20.6"
+ bin:
+ miniflare: bootstrap.js
+ checksum: 89cd180344cdc425e851a035ff164965aa708541f98c9cb81a5679c95d40c58d37c85b08dd0627a1574872d77543a7c43a67779fd62c5e94373ae80fe4bafa71
+ languageName: node
+ linkType: hard
+
"minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
version: 3.1.2
resolution: "minimatch@npm:3.1.2"
@@ -11699,6 +12166,15 @@ __metadata:
languageName: node
linkType: hard
+"mustache@npm:^4.2.0":
+ version: 4.2.0
+ resolution: "mustache@npm:4.2.0"
+ bin:
+ mustache: bin/mustache
+ checksum: 1f8197e8a19e63645a786581d58c41df7853da26702dbc005193e2437c98ca49b255345c173d50c08fe4b4dbb363e53cb655ecc570791f8deb09887248dd34a2
+ languageName: node
+ linkType: hard
+
"mz@npm:^2.7.0":
version: 2.7.0
resolution: "mz@npm:2.7.0"
@@ -11710,7 +12186,7 @@ __metadata:
languageName: node
linkType: hard
-"nanoid@npm:^3.3.6, nanoid@npm:^3.3.7":
+"nanoid@npm:^3.3.3, nanoid@npm:^3.3.6, nanoid@npm:^3.3.7":
version: 3.3.7
resolution: "nanoid@npm:3.3.7"
bin:
@@ -11875,6 +12351,13 @@ __metadata:
languageName: node
linkType: hard
+"node-forge@npm:^1":
+ version: 1.3.1
+ resolution: "node-forge@npm:1.3.1"
+ checksum: e882819b251a4321f9fc1d67c85d1501d3004b4ee889af822fd07f64de3d1a8e272ff00b689570af0465d65d6bf5074df9c76e900e0aff23e60b847f2a46fbe8
+ languageName: node
+ linkType: hard
+
"node-gyp@npm:latest":
version: 10.0.1
resolution: "node-gyp@npm:10.0.1"
@@ -12110,6 +12593,13 @@ __metadata:
languageName: node
linkType: hard
+"papaparse@npm:^5.4.1":
+ version: 5.4.1
+ resolution: "papaparse@npm:5.4.1"
+ checksum: 201f37c4813453fed5bfb4c01816696b099d2db9ff1e8fb610acc4771fdde91d2a22b6094721edb0fedb21ca3c46f04263f68be4beb3e35b8c72278f0cedc7b7
+ languageName: node
+ linkType: hard
+
"param-case@npm:^3.0.4":
version: 3.0.4
resolution: "param-case@npm:3.0.4"
@@ -12296,6 +12786,13 @@ __metadata:
languageName: node
linkType: hard
+"path-to-regexp@npm:^6.2.0":
+ version: 6.2.1
+ resolution: "path-to-regexp@npm:6.2.1"
+ checksum: 7a73811ca703e5c199e5b50b9649ab8f6f7b458a37f7dff9ea338815203f5b1f95fe8cb24d4fdfe2eab5d67ce43562d92534330babca35cdf3231f966adb9360
+ languageName: node
+ linkType: hard
+
"path-type@npm:^4.0.0":
version: 4.0.0
resolution: "path-type@npm:4.0.0"
@@ -12310,9 +12807,9 @@ __metadata:
languageName: node
linkType: hard
-"payload@npm:^2.6.0":
- version: 2.7.0
- resolution: "payload@npm:2.7.0"
+"payload@npm:^2.8.2":
+ version: 2.8.2
+ resolution: "payload@npm:2.8.2"
dependencies:
"@date-io/date-fns": "npm:2.16.0"
"@dnd-kit/core": "npm:6.0.8"
@@ -12405,7 +12902,7 @@ __metadata:
uuid: "npm:9.0.1"
bin:
payload: bin.js
- checksum: 40f226a37c1a81a8fb1c5c88855588163975e24f55efa24f25e66fae2720279339d44f035ed5397b5a8111a93f902e178218f1b4eaf7e57e04d4fa3844006ed5
+ checksum: 10fb2fc0cc5fcff2b0a633d960c9209a91e6383935e0baa4121fa933098dc41f3ceac41afcc4b881105efc5c8be8a3462b5e292e4278068ea5b77f186e81e6ee
languageName: node
linkType: hard
@@ -13483,6 +13980,13 @@ __metadata:
languageName: node
linkType: hard
+"printable-characters@npm:^1.0.42":
+ version: 1.0.42
+ resolution: "printable-characters@npm:1.0.42"
+ checksum: 7c94d94c6041a37c385af770c7402ad5a2e8a3429ca4d2505a9f19fde39bac9a8fd1edfbfa02f1eae5b4b0f3536b6b8ee6c84621f7c0fcb41476b2df6ee20e4b
+ languageName: node
+ linkType: hard
+
"probe-image-size@npm:6.0.0":
version: 6.0.0
resolution: "probe-image-size@npm:6.0.0"
@@ -14036,7 +14540,7 @@ __metadata:
languageName: node
linkType: hard
-"react@npm:18.2.0, react@npm:^18":
+"react@npm:18.2.0, react@npm:>=16, react@npm:^18":
version: 18.2.0
resolution: "react@npm:18.2.0"
dependencies:
@@ -14267,7 +14771,14 @@ __metadata:
languageName: node
linkType: hard
-"resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.9.0":
+"resolve.exports@npm:^2.0.2":
+ version: 2.0.2
+ resolution: "resolve.exports@npm:2.0.2"
+ checksum: cc4cffdc25447cf34730f388dca5021156ba9302a3bad3d7f168e790dc74b2827dff603f1bc6ad3d299bac269828dca96dd77e036dc9fba6a2a1807c47ab5c98
+ languageName: node
+ linkType: hard
+
+"resolve@npm:^1.14.2, resolve@npm:^1.19.0, resolve@npm:^1.22.8, resolve@npm:^1.9.0":
version: 1.22.8
resolution: "resolve@npm:1.22.8"
dependencies:
@@ -14280,7 +14791,7 @@ __metadata:
languageName: node
linkType: hard
-"resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.9.0#optional!builtin":
+"resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.19.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin, resolve@patch:resolve@npm%3A^1.9.0#optional!builtin":
version: 1.22.8
resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d"
dependencies:
@@ -14325,6 +14836,26 @@ __metadata:
languageName: node
linkType: hard
+"rollup-plugin-inject@npm:^3.0.0":
+ version: 3.0.2
+ resolution: "rollup-plugin-inject@npm:3.0.2"
+ dependencies:
+ estree-walker: "npm:^0.6.1"
+ magic-string: "npm:^0.25.3"
+ rollup-pluginutils: "npm:^2.8.1"
+ checksum: 35b9d955039b56b43750a9e458bb51b7956b048b6d3ca57b1f03462aa5a0cb176d1b677d95e909b64eee4e9adf73c02f569ad8c0ab5aafdec818ff51700c114c
+ languageName: node
+ linkType: hard
+
+"rollup-plugin-node-polyfills@npm:^0.2.1":
+ version: 0.2.1
+ resolution: "rollup-plugin-node-polyfills@npm:0.2.1"
+ dependencies:
+ rollup-plugin-inject: "npm:^3.0.0"
+ checksum: 30f9e09cbbf979b1212e0c455d74c3a061994fc19ddf160da4634b11377222cea5903a5ba05db66be849f550cde9ffc80ecbfcfb48544045d08bfc408501417d
+ languageName: node
+ linkType: hard
+
"rollup-plugin-terser@npm:^7.0.0":
version: 7.0.2
resolution: "rollup-plugin-terser@npm:7.0.2"
@@ -14339,6 +14870,15 @@ __metadata:
languageName: node
linkType: hard
+"rollup-pluginutils@npm:^2.8.1":
+ version: 2.8.2
+ resolution: "rollup-pluginutils@npm:2.8.2"
+ dependencies:
+ estree-walker: "npm:^0.6.1"
+ checksum: 20947bec5a5dd68b5c5c8423911e6e7c0ad834c451f1a929b1f4e2bc08836ad3f1a722ef2bfcbeca921870a0a283f13f064a317dc7a6768496e98c9a641ba290
+ languageName: node
+ linkType: hard
+
"rollup@npm:^2.43.1":
version: 2.79.1
resolution: "rollup@npm:2.79.1"
@@ -14535,6 +15075,16 @@ __metadata:
languageName: node
linkType: hard
+"selfsigned@npm:^2.0.1":
+ version: 2.4.1
+ resolution: "selfsigned@npm:2.4.1"
+ dependencies:
+ "@types/node-forge": "npm:^1.3.0"
+ node-forge: "npm:^1"
+ checksum: 521829ec36ea042f7e9963bf1da2ed040a815cf774422544b112ec53b7edc0bc50a0f8cc2ae7aa6cc19afa967c641fd96a15de0fc650c68651e41277d2e1df09
+ languageName: node
+ linkType: hard
+
"semver@npm:7.5.4, semver@npm:^7.3.5, semver@npm:^7.3.8, semver@npm:^7.5.4":
version: 7.5.4
resolution: "semver@npm:7.5.4"
@@ -14932,6 +15482,13 @@ __metadata:
languageName: node
linkType: hard
+"source-map@npm:0.6.1, source-map@npm:^0.6.0, source-map@npm:^0.6.1, source-map@npm:~0.6.0, source-map@npm:~0.6.1":
+ version: 0.6.1
+ resolution: "source-map@npm:0.6.1"
+ checksum: ab55398007c5e5532957cb0beee2368529618ac0ab372d789806f5718123cc4367d57de3904b4e6a4170eb5a0b0f41373066d02ca0735a0c4d75c7d328d3e011
+ languageName: node
+ linkType: hard
+
"source-map@npm:^0.5.7":
version: 0.5.7
resolution: "source-map@npm:0.5.7"
@@ -14939,13 +15496,6 @@ __metadata:
languageName: node
linkType: hard
-"source-map@npm:^0.6.0, source-map@npm:~0.6.0, source-map@npm:~0.6.1":
- version: 0.6.1
- resolution: "source-map@npm:0.6.1"
- checksum: ab55398007c5e5532957cb0beee2368529618ac0ab372d789806f5718123cc4367d57de3904b4e6a4170eb5a0b0f41373066d02ca0735a0c4d75c7d328d3e011
- languageName: node
- linkType: hard
-
"source-map@npm:^0.8.0-beta.0":
version: 0.8.0-beta.0
resolution: "source-map@npm:0.8.0-beta.0"
@@ -14987,6 +15537,16 @@ __metadata:
languageName: node
linkType: hard
+"stacktracey@npm:^2.1.8":
+ version: 2.1.8
+ resolution: "stacktracey@npm:2.1.8"
+ dependencies:
+ as-table: "npm:^1.0.36"
+ get-source: "npm:^2.0.12"
+ checksum: e17357d0a532d303138899b910ab660572009a1f4cde1cbf73b99416957a2378e6e1c791b3c31b043cf7c5f37647da1dd114e66c9203f23c65b34f783665405b
+ languageName: node
+ linkType: hard
+
"state-local@npm:^1.0.6":
version: 1.0.7
resolution: "state-local@npm:1.0.7"
@@ -15010,6 +15570,13 @@ __metadata:
languageName: node
linkType: hard
+"stoppable@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "stoppable@npm:1.1.0"
+ checksum: ba91b65e6442bf6f01ce837a727ece597a977ed92a05cb9aea6bf446c5e0dcbccc28f31b793afa8aedd8f34baaf3335398d35f903938d5493f7fbe386a1e090e
+ languageName: node
+ linkType: hard
+
"stream-browserify@npm:3.0.0":
version: 3.0.0
resolution: "stream-browserify@npm:3.0.0"
@@ -15667,7 +16234,7 @@ __metadata:
languageName: node
linkType: hard
-"tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.5.0":
+"tslib@npm:^2.0.0, tslib@npm:^2.0.3, tslib@npm:^2.1.0, tslib@npm:^2.2.0, tslib@npm:^2.3.1, tslib@npm:^2.4.0, tslib@npm:^2.5.0":
version: 2.6.2
resolution: "tslib@npm:2.6.2"
checksum: e03a8a4271152c8b26604ed45535954c0a45296e32445b4b87f8a5abdb2421f40b59b4ca437c4346af0f28179780d604094eb64546bee2019d903d01c6c19bdb
@@ -15823,6 +16390,15 @@ __metadata:
languageName: node
linkType: hard
+"undici@npm:^5.28.2":
+ version: 5.28.2
+ resolution: "undici@npm:5.28.2"
+ dependencies:
+ "@fastify/busboy": "npm:^2.0.0"
+ checksum: 34385ad9b3ba85309972ee3c1b426dcd19b94a5a6aa9c54499b5f48436c0ecc13a9b1e756a7c6a953eaefa9f4263890625ece5f2719fd774b0852204f5e4d5f9
+ languageName: node
+ linkType: hard
+
"unicode-canonical-property-names-ecmascript@npm:^2.0.0":
version: 2.0.0
resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0"
@@ -16129,13 +16705,15 @@ __metadata:
dependencies:
"@aws-sdk/client-s3": "npm:^3.490.0"
"@aws-sdk/lib-storage": "npm:^3.490.0"
+ "@chakra-ui/icons": "npm:^2.1.1"
"@chakra-ui/next-js": "npm:^2.2.0"
"@chakra-ui/react": "npm:^2.8.2"
"@ducanh2912/next-pwa": "npm:^10.1.0"
"@emotion/react": "npm:^11.11.1"
"@emotion/styled": "npm:^11.11.0"
+ "@gsap/react": "npm:^2.1.0"
"@payloadcms/bundler-webpack": "npm:^1.0.5"
- "@payloadcms/db-postgres": "npm:^0.3.0"
+ "@payloadcms/db-postgres": "npm:^0.4.0"
"@payloadcms/next-payload": "npm:^0.1.11"
"@payloadcms/plugin-cloud-storage": "npm:^1.1.1"
"@payloadcms/richtext-slate": "npm:^1.3.1"
@@ -16146,16 +16724,19 @@ __metadata:
"@trpc/react-query": "npm:^10.44.1"
"@trpc/server": "npm:^10.44.1"
"@types/node": "npm:^20"
+ "@types/papaparse": "npm:^5"
"@types/react": "npm:^18"
"@types/react-dom": "npm:^18"
aws-crt: "npm:^1.20.1"
cookies-next: "npm:^4.1.0"
dotenv: "npm:^16.3.1"
framer-motion: "npm:^10.16.16"
+ gsap: "npm:^3.12.5"
ignore-styles: "npm:^5.0.1"
jwt-decode: "npm:^4.0.0"
next: "npm:13.5.5"
- payload: "npm:^2.6.0"
+ papaparse: "npm:^5.4.1"
+ payload: "npm:^2.8.2"
react: "npm:^18"
react-dom: "npm:^18"
react-hook-form: "npm:^7.49.2"
@@ -16658,6 +17239,61 @@ __metadata:
languageName: node
linkType: hard
+"workerd@npm:1.20231218.0":
+ version: 1.20231218.0
+ resolution: "workerd@npm:1.20231218.0"
+ dependencies:
+ "@cloudflare/workerd-darwin-64": "npm:1.20231218.0"
+ "@cloudflare/workerd-darwin-arm64": "npm:1.20231218.0"
+ "@cloudflare/workerd-linux-64": "npm:1.20231218.0"
+ "@cloudflare/workerd-linux-arm64": "npm:1.20231218.0"
+ "@cloudflare/workerd-windows-64": "npm:1.20231218.0"
+ dependenciesMeta:
+ "@cloudflare/workerd-darwin-64":
+ optional: true
+ "@cloudflare/workerd-darwin-arm64":
+ optional: true
+ "@cloudflare/workerd-linux-64":
+ optional: true
+ "@cloudflare/workerd-linux-arm64":
+ optional: true
+ "@cloudflare/workerd-windows-64":
+ optional: true
+ bin:
+ workerd: bin/workerd
+ checksum: 67121048c4b2ca3d9a9ba5971a3f06f013792c39ec74be8a89d508460fe815677379ee0d3d6ee9272b9f670a38af35c6df4728059f15545d3421ceb8a5506e41
+ languageName: node
+ linkType: hard
+
+"wrangler@npm:^3.7.0":
+ version: 3.24.0
+ resolution: "wrangler@npm:3.24.0"
+ dependencies:
+ "@cloudflare/kv-asset-handler": "npm:^0.2.0"
+ "@esbuild-plugins/node-globals-polyfill": "npm:^0.2.3"
+ "@esbuild-plugins/node-modules-polyfill": "npm:^0.2.2"
+ blake3-wasm: "npm:^2.1.5"
+ chokidar: "npm:^3.5.3"
+ esbuild: "npm:0.17.19"
+ fsevents: "npm:~2.3.2"
+ miniflare: "npm:3.20231218.3"
+ nanoid: "npm:^3.3.3"
+ path-to-regexp: "npm:^6.2.0"
+ resolve: "npm:^1.22.8"
+ resolve.exports: "npm:^2.0.2"
+ selfsigned: "npm:^2.0.1"
+ source-map: "npm:0.6.1"
+ xxhash-wasm: "npm:^1.0.1"
+ dependenciesMeta:
+ fsevents:
+ optional: true
+ bin:
+ wrangler: bin/wrangler.js
+ wrangler2: bin/wrangler.js
+ checksum: 4c12568b8a8cc0450cf3dea44db22ef91d1e567b043d3cc49d029534b2dda1460283b35011a7d4ad0c14e2a1c78efcfda952e2bf5395c6233f361d0ea7289325
+ languageName: node
+ linkType: hard
+
"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0":
version: 7.0.0
resolution: "wrap-ansi@npm:7.0.0"
@@ -16687,7 +17323,7 @@ __metadata:
languageName: node
linkType: hard
-"ws@npm:*, ws@npm:^8.13.0":
+"ws@npm:*, ws@npm:^8.11.0, ws@npm:^8.13.0":
version: 8.16.0
resolution: "ws@npm:8.16.0"
peerDependencies:
@@ -16736,6 +17372,13 @@ __metadata:
languageName: node
linkType: hard
+"xxhash-wasm@npm:^1.0.1":
+ version: 1.0.2
+ resolution: "xxhash-wasm@npm:1.0.2"
+ checksum: 5ba899d9216d9897de2d61a5331b16c99226e75ce47895fc8c730bac5cb00e6e50856dd8f489c12b3012f0fc81b6894806b2e44d2eb3cc7843919793485a30d1
+ languageName: node
+ linkType: hard
+
"yallist@npm:^3.0.2":
version: 3.1.1
resolution: "yallist@npm:3.1.1"
@@ -16757,7 +17400,18 @@ __metadata:
languageName: node
linkType: hard
-"zod@npm:^3.20.2, zod@npm:^3.22.4":
+"youch@npm:^3.2.2":
+ version: 3.3.3
+ resolution: "youch@npm:3.3.3"
+ dependencies:
+ cookie: "npm:^0.5.0"
+ mustache: "npm:^4.2.0"
+ stacktracey: "npm:^2.1.8"
+ checksum: 6e5dd4be39ea737fb557fe0647855ce7f0e2182330342cc5e2315a688e0950683967abbc43dd6452b80f39271b14872c390a6e96009f2475905d6be824d38109
+ languageName: node
+ linkType: hard
+
+"zod@npm:^3.20.2, zod@npm:^3.20.6, zod@npm:^3.22.4":
version: 3.22.4
resolution: "zod@npm:3.22.4"
checksum: 7578ab283dac0eee66a0ad0fc4a7f28c43e6745aadb3a529f59a4b851aa10872b3890398b3160f257f4b6817b4ce643debdda4fb21a2c040adda7862cab0a587