diff --git a/client/pull_request_template.md b/.github/pull_request_template.md similarity index 100% rename from client/pull_request_template.md rename to .github/pull_request_template.md diff --git a/.github/workflows/api-tests.yml b/.github/workflows/api-tests.yml index c330af25..ded53944 100644 --- a/.github/workflows/api-tests.yml +++ b/.github/workflows/api-tests.yml @@ -18,14 +18,12 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Use Node.js 20.10 + - name: Node setup uses: actions/setup-node@v4 with: - node-version-file: 'api/.nvmrc' + node-version-file: '.nvmrc' - uses: pnpm/action-setup@v4 - with: - version: 9 - name: Install API dependencies working-directory: api diff --git a/.github/workflows/client-tests.yml b/.github/workflows/client-tests.yml index 6fc90746..7c1b8756 100644 --- a/.github/workflows/client-tests.yml +++ b/.github/workflows/client-tests.yml @@ -18,14 +18,12 @@ jobs: - name: Checkout code uses: actions/checkout@v4 - - name: Use Node.js 20.10 + - name: Node setup uses: actions/setup-node@v4 with: - node-version-file: 'client/.nvmrc' + node-version-file: '.nvmrc' - uses: pnpm/action-setup@v4 - with: - version: 9 - name: Install Client dependencies working-directory: client diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..0e4f87e3 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v22.2.0 \ No newline at end of file diff --git a/README.md b/README.md index fb5c7697..a9f84402 100644 --- a/README.md +++ b/README.md @@ -20,15 +20,15 @@ We use `pnpm` for managing packages in this project. This allows us to efficient Here are the npm scripts that you can run: -- `pnpm start:api:dev`: Starts the backend application in development mode. -- `pnpm start:client:dev`: Starts the frontend application in development mode. -- `pnpm install:client`: Installs the client application dependencies. -- `pnpm install:api`: Installs the API application dependencies. -- `pnpm build:client`: Builds the client application for production. -- `pnpm build:api`: Builds the API application for production. -- `pnpm start:client:prod`: Starts the client application in production mode. -- `pnpm start:api:prod`: Starts the API application in production mode. -- `pnpm start:prod`: Builds and starts both applications in production mode. +- `pnpm api:dev`: Starts the backend application in development mode. +- `pnpm client:dev`: Starts the frontend application in development mode. +- `pnpm client:deps`: Installs the client application dependencies. +- `pnpm api:deps`: Installs the API application dependencies. +- `pnpm client:build`: Builds the client application for production. +- `pnpm api:build`: Builds the API application for production. +- `pnpm client:prod`: Starts the client application in production mode. +- `pnpm api:prod`: Starts the API application in production mode. +- `pnpm all:prod`: Builds and starts both applications in production mode. ## TypeScript Configuration diff --git a/api/.nvmrc b/api/.nvmrc deleted file mode 100644 index 94868253..00000000 --- a/api/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -20.10.0 \ No newline at end of file diff --git a/client/.nvmrc b/client/.nvmrc deleted file mode 100644 index 94868253..00000000 --- a/client/.nvmrc +++ /dev/null @@ -1 +0,0 @@ -20.10.0 \ No newline at end of file diff --git a/client/package.json b/client/package.json index 7ef8f2fa..3618cab8 100644 --- a/client/package.json +++ b/client/package.json @@ -10,6 +10,8 @@ "test": "jest" }, "dependencies": { + "@tanstack/react-query": "^5.36.2", + "@ts-rest/react-query": "^3.45.2", "clsx": "2.1.1", "lucide-react": "0.378.0", "next": "14.2.3", @@ -18,7 +20,6 @@ "tailwind-merge": "2.3.0" }, "devDependencies": { - "shared": "workspace:*", "@testing-library/jest-dom": "^5.4.5", "@testing-library/react": "^15.0.7", "@types/jest": "^29.5.12", @@ -36,8 +37,9 @@ "jest-environment-jsdom": "^29.7.0", "postcss": "^8", "prettier": "^3.2.5", + "shared": "workspace:*", "tailwindcss": "^3.4.1", - "typescript": "^5.1.3", - "ts-node": "^10.9.2" + "ts-node": "^10.9.2", + "typescript": "^5.1.3" } } diff --git a/client/src/app/layout.tsx b/client/src/app/layout.tsx index a0095bc1..70f686ff 100644 --- a/client/src/app/layout.tsx +++ b/client/src/app/layout.tsx @@ -1,7 +1,7 @@ import { Inter } from "next/font/google"; import type { Metadata } from "next"; -import "@client/src/app/globals.css"; +import "@/app/globals.css"; const inter = Inter({ subsets: ["latin"] }); diff --git a/client/src/containers/coming-soon/index.tsx b/client/src/containers/coming-soon/index.tsx index 91c5ec3d..001fd1c3 100644 --- a/client/src/containers/coming-soon/index.tsx +++ b/client/src/containers/coming-soon/index.tsx @@ -2,7 +2,8 @@ import Image from "next/image"; import { BarChartHorizontal, Filter } from "lucide-react"; -import Wrapper from "@client/src/containers/wrapper"; +import Wrapper from "@/containers/wrapper"; + export default function ComingSoon() { return ( diff --git a/client/src/containers/wrapper.tsx b/client/src/containers/wrapper.tsx index 84857df2..857ffd78 100644 --- a/client/src/containers/wrapper.tsx +++ b/client/src/containers/wrapper.tsx @@ -1,6 +1,6 @@ import { ReactNode } from "react"; -import { cn } from "@client/src/utils/cn"; +import { cn } from "@/utils/cn"; const Wrapper = ({ children, diff --git a/client/tsconfig.json b/client/tsconfig.json index 82cc363a..47fe4dff 100644 --- a/client/tsconfig.json +++ b/client/tsconfig.json @@ -11,19 +11,25 @@ "strict": true, "noEmit": true, "esModuleInterop": true, - "allowSyntheticDefaultImports": true, "module": "esnext", "moduleResolution": "bundler", "resolveJsonModule": true, "isolatedModules": true, + "strictPropertyInitialization": false, "jsx": "preserve", "incremental": true, - "strictPropertyInitialization": false, "plugins": [ { "name": "next" } ], + "baseUrl": ".", + "paths": { + "@shared/*": ["../shared/*"], + "@/*": [ + "./src/*" + ] + } }, "include": [ "src/**/*", diff --git a/package.json b/package.json index 1f9cf1a9..505159e0 100644 --- a/package.json +++ b/package.json @@ -1,16 +1,17 @@ { "name": "4-growth", "version": "1.0.0", - "description": "4-growth mono-repo", + "description": "4-growth platform", "scripts": { - "start:api:dev": "pnpm --filter api run start:dev", - "start:client:dev": "pnpm --filter client run dev", - "install:client": "pnpm --filter client install", - "install:api": "pnpm --filter api install", - "build:client": "pnpm --filter client run build", - "build:api": "pnpm --filter api run build", - "start:client:prod": "pnpm --filter client run start", - "start:api:prod": "pnpm --filter api run start:prod", - "start:prod": "pnpm run build:client && pnpm run build:api && pnpm run start:client:prod & pnpm run start:api:prod" - } + "api:deps": "pnpm --filter api install", + "api:dev": "pnpm --filter api run start:dev", + "api:build": "pnpm --filter api run build", + "api:prod": "pnpm --filter api run start:prod", + "client:deps": "pnpm --filter client install", + "client:dev": "pnpm --filter client run dev", + "client:build": "pnpm --filter client run build", + "client:prod": "pnpm --filter client run start", + "all:prod": "pnpm run build:client && pnpm run build:api && pnpm run start:client:prod & pnpm run start:api:prod" + }, + "packageManager": "pnpm@9.1.1" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b5520ce1..d371209c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -104,6 +104,12 @@ importers: client: dependencies: + '@tanstack/react-query': + specifier: ^5.36.2 + version: 5.36.2(react@18.3.1) + '@ts-rest/react-query': + specifier: ^3.45.2 + version: 3.45.2(@tanstack/react-query@5.36.2(react@18.3.1))(react@18.3.1)(zod@3.23.8) clsx: specifier: 2.1.1 version: 2.1.1 @@ -192,6 +198,12 @@ importers: '@ts-rest/core': specifier: ^3.45.2 version: 3.45.2(zod@3.23.8) + '@typescript-eslint/eslint-plugin': + specifier: 7.9.0 + version: 7.9.0(@typescript-eslint/parser@7.9.0(eslint@8.57.0)(typescript@5.4.5))(eslint@8.57.0)(typescript@5.4.5) + '@typescript-eslint/parser': + specifier: 7.9.0 + version: 7.9.0(eslint@8.57.0)(typescript@5.4.5) class-transformer: specifier: ^0.5.1 version: 0.5.1 @@ -201,9 +213,18 @@ importers: config: specifier: ^3.3.11 version: 3.3.11 + eslint: + specifier: ^8.42.0 + version: 8.57.0 + eslint-config-prettier: + specifier: ^9.0.0 + version: 9.1.0(eslint@8.57.0) + eslint-plugin-prettier: + specifier: ^5.0.0 + version: 5.1.3(@types/eslint@8.56.10)(eslint-config-prettier@9.1.0(eslint@8.57.0))(eslint@8.57.0)(prettier@3.2.5) typeorm: specifier: ^0.3.20 - version: 0.3.20(ts-node@10.9.2) + version: 0.3.20(ts-node@10.9.2(typescript@5.4.5)) zod: specifier: ^3.23.8 version: 3.23.8 @@ -739,6 +760,14 @@ packages: '@swc/helpers@0.5.5': resolution: {integrity: sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==} + '@tanstack/query-core@5.36.1': + resolution: {integrity: sha512-BteWYEPUcucEu3NBcDAgKuI4U25R9aPrHSP6YSf2NvaD2pSlIQTdqOfLRsxH9WdRYg7k0Uom35Uacb6nvbIMJg==} + + '@tanstack/react-query@5.36.2': + resolution: {integrity: sha512-bHNa+5dead+j6SA8WVlEOPxcGfteVFgdyFTCFcxBgjnPf0fFpHUc7aNZBCnvmPXqy/BeQa9zTuU9ectb7i8ZXA==} + peerDependencies: + react: ^18.0.0 + '@testing-library/dom@10.1.0': resolution: {integrity: sha512-wdsYKy5zupPyLCW2Je5DLHSxSfbIp6h80WoHOQc+RPtmPGA52O9x5MJEkv92Sjonpq+poOAtUKhh1kBGAXBrNA==} engines: {node: '>=18'} @@ -770,6 +799,16 @@ packages: zod: optional: true + '@ts-rest/react-query@3.45.2': + resolution: {integrity: sha512-OFl54tb+d2vJsPENr0ehmb2KrXmXTbwEDMmoIW7iyAHEIbPiL03QreeiFykZpsRDdTUjQJY2TgOmFKCCtLozWA==} + peerDependencies: + '@tanstack/react-query': ^4.0.0 + react: ^16.8.0 || ^17.0.0 || ^18.0.0 + zod: ^3.22.3 + peerDependenciesMeta: + zod: + optional: true + '@tsconfig/node10@1.0.11': resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} @@ -4665,7 +4704,7 @@ snapshots: '@nestjs/core': 10.3.8(@nestjs/common@10.3.8(class-transformer@0.5.1)(class-validator@0.14.1)(reflect-metadata@0.2.2)(rxjs@7.8.1))(@nestjs/platform-express@10.3.8)(reflect-metadata@0.2.2)(rxjs@7.8.1) reflect-metadata: 0.2.2 rxjs: 7.8.1 - typeorm: 0.3.20(ts-node@10.9.2) + typeorm: 0.3.20(ts-node@10.9.2(typescript@5.4.5)) uuid: 9.0.1 '@next/env@14.2.3': {} @@ -4747,6 +4786,13 @@ snapshots: '@swc/counter': 0.1.3 tslib: 2.6.2 + '@tanstack/query-core@5.36.1': {} + + '@tanstack/react-query@5.36.2(react@18.3.1)': + dependencies: + '@tanstack/query-core': 5.36.1 + react: 18.3.1 + '@testing-library/dom@10.1.0': dependencies: '@babel/code-frame': 7.24.2 @@ -4786,6 +4832,13 @@ snapshots: optionalDependencies: zod: 3.23.8 + '@ts-rest/react-query@3.45.2(@tanstack/react-query@5.36.2(react@18.3.1))(react@18.3.1)(zod@3.23.8)': + dependencies: + '@tanstack/react-query': 5.36.2(react@18.3.1) + react: 18.3.1 + optionalDependencies: + zod: 3.23.8 + '@tsconfig/node10@1.0.11': {} '@tsconfig/node12@1.0.11': {} @@ -8396,7 +8449,7 @@ snapshots: typedarray@0.0.6: {} - typeorm@0.3.20(ts-node@10.9.2): + typeorm@0.3.20(ts-node@10.9.2(typescript@5.4.5)): dependencies: '@sqltools/formatter': 1.2.5 app-root-path: 3.1.0 diff --git a/shared/.eslintignore b/shared/.eslintignore new file mode 100644 index 00000000..07e6e472 --- /dev/null +++ b/shared/.eslintignore @@ -0,0 +1 @@ +/node_modules diff --git a/shared/.eslintrc.js b/shared/.eslintrc.js new file mode 100644 index 00000000..a8a2afe9 --- /dev/null +++ b/shared/.eslintrc.js @@ -0,0 +1,24 @@ +module.exports = { + parser: '@typescript-eslint/parser', + parserOptions: { + project: 'tsconfig.json', + tsconfigRootDir: __dirname, + sourceType: 'module', + }, + plugins: ['@typescript-eslint/eslint-plugin'], + extends: [ + 'plugin:@typescript-eslint/recommended', + 'plugin:prettier/recommended', + ], + root: true, + env: { + node: true, + }, + ignorePatterns: ['.eslintrc.js'], + rules: { + '@typescript-eslint/interface-name-prefix': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-explicit-any': 'off', + }, +}; diff --git a/shared/.prettierrc b/shared/.prettierrc new file mode 100644 index 00000000..dcb72794 --- /dev/null +++ b/shared/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "trailingComma": "all" +} \ No newline at end of file diff --git a/shared/contracts/user.contract.ts b/shared/contracts/user.contract.ts index 321dbc59..2a65dc70 100644 --- a/shared/contracts/user.contract.ts +++ b/shared/contracts/user.contract.ts @@ -1,26 +1,41 @@ -import { initContract } from "@ts-rest/core"; -import { User } from "@shared/dto/users/user.entity"; -import { UpdateUserDto } from "@shared/dto/users/update-user.dto"; -import { CreateUserDto } from "@shared/dto/users/create-user.dto"; +import { initContract } from '@ts-rest/core'; +import { User } from '@shared/dto/users/user.entity'; +import { UpdateUserDto } from '@shared/dto/users/update-user.dto'; +import { CreateUserDto } from '@shared/dto/users/create-user.dto'; + +import * as z from 'zod'; const contract = initContract(); export const userContract = contract.router({ createUser: { - method: "POST", - path: "/users", + method: 'POST', + path: '/users', responses: { 201: contract.type(), }, body: contract.type(), - summary: "Create a new user", + summary: 'Create a new user', }, updateUser: { - method: "PUT", - path: "/users/:id", + method: 'PUT', + path: '/users/:id', responses: { 200: contract.type(), }, body: contract.type(), - summary: "Update an existing user", + summary: 'Update an existing user', + }, + getUsers: { + method: 'GET', + path: '/users', + responses: { + 200: contract.type(), + }, + query: z.object({ + take: z.string().transform(Number).optional(), + skip: z.string().transform(Number).optional(), + search: z.string().optional(), + }), + summary: 'Get all users', }, }); diff --git a/shared/dto/users/user.entity.ts b/shared/dto/users/user.entity.ts index 854b350d..95497106 100644 --- a/shared/dto/users/user.entity.ts +++ b/shared/dto/users/user.entity.ts @@ -1,12 +1,11 @@ import { - BaseEntity, Column, CreateDateColumn, PrimaryGeneratedColumn, UpdateDateColumn, } from 'typeorm'; -export class User extends BaseEntity { +export class User { @PrimaryGeneratedColumn() id: number; diff --git a/shared/package.json b/shared/package.json index 16cda4f2..b56313d9 100644 --- a/shared/package.json +++ b/shared/package.json @@ -1,13 +1,17 @@ { "name": "shared", "private": true, - "packageManager": "pnpm@9.1.1", "dependencies": { "@ts-rest/core": "^3.45.2", + "@typescript-eslint/eslint-plugin": "7.9.0", + "@typescript-eslint/parser": "7.9.0", + "class-transformer": "^0.5.1", + "class-validator": "^0.14.1", "config": "^3.3.11", + "eslint": "^8.42.0", + "eslint-config-prettier": "^9.0.0", + "eslint-plugin-prettier": "^5.0.0", "typeorm": "^0.3.20", - "zod": "^3.23.8", - "class-transformer": "^0.5.1", - "class-validator": "^0.14.1" + "zod": "^3.23.8" } }