From e17d338446ffd0ca551face19ea5a62a129efb3f Mon Sep 17 00:00:00 2001 From: MikeTeddyOmondi Date: Thu, 30 May 2024 05:57:31 +0300 Subject: [PATCH] Updated application for production --- .env.example | 23 +++ .gitignore | 2 + CHANGELOG.md | 10 + backend/.dockerignore | 9 + backend/.env.example | 10 + backend/.justfile | 27 +++ backend/Dockerfile | 19 ++ backend/Dockerfile.prod | 28 +++ backend/package.json | 7 +- backend/yarn.lock | 85 ++++++++- compose.yml | 75 ++++++++ frontend/.dockerignore | 6 + frontend/.env.example | 1 + frontend/.justfile | 22 +++ frontend/Dockerfile | 8 + frontend/next.config.js | 17 +- frontend/package-lock.json | 9 - frontend/package.json | 1 - frontend/src/components/InvoiceForm.tsx | 233 +++++++++++++++--------- frontend/src/components/Invoices.tsx | 196 +++++++++++++------- frontend/src/pages/api/hello.ts | 13 -- 21 files changed, 615 insertions(+), 186 deletions(-) create mode 100644 .env.example create mode 100644 .gitignore create mode 100644 CHANGELOG.md create mode 100644 backend/.dockerignore create mode 100644 backend/.justfile create mode 100644 backend/Dockerfile create mode 100644 backend/Dockerfile.prod create mode 100644 compose.yml create mode 100644 frontend/.dockerignore create mode 100644 frontend/.env.example create mode 100644 frontend/.justfile create mode 100644 frontend/Dockerfile delete mode 100644 frontend/src/pages/api/hello.ts diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..323726c --- /dev/null +++ b/.env.example @@ -0,0 +1,23 @@ +# Frontend +NEXT_PUBLIC_STRAPI_BACKEND_SERVER="http://backend:1337" + +# Backend +HOST=0.0.0.0 +PORT=1337 +APP_KEYS="jP8pb1lYsAhnmURarewxhA==,34xnLMYHY5jiU7ONTstTqQ==" +API_TOKEN_SALT="I0vcDalag4CrYczTEWBEDeM2yCJkza4tqtIl3/uhDn8=" +ADMIN_JWT_SECRET="Sxtp8ZJi3lc0ZsAXZsP7phgUdajDFhOt8LzT+WXPCmXaMdRxXA35Cxud6G4eseoHEpq0UYzhCjzUvSuR4zzrg==" +TRANSFER_TOKEN_SALT="409wAPn4uEZOgPY3jLGrEb/QnQ+HlM7eRdJEmcGYcM8=" +JWT_SECRET="ENOgRF5qx5vb8ynywbbGA1MJeQYWpzx1sZ7mSwNCI+dr3fqviCOZb1FaEc6zbAOPhvU6/DeAVRw+MY6MVPPbFw==" +NODE_ENV="production" + +# Database +DATABASE_CLIENT=postgres +DATABASE_URL=postgres://strapi:strapi@database:5432/strapi +DATABASE_HOST=127.0.0.1 +DATABASE_PORT=5432 +DATABASE_NAME=strapi +DATABASE_USERNAME=strapi +DATABASE_PASSWORD=strapi +DATABASE_SSL=false + diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..00dd011 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +**/*.env +.env diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..efb0839 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ + +# Proposed Changes: + +- Removed `appDir` at experimental feature in next.config.js +- Removed `@next/font` already built-in in Nextjs 14 +- Added `Dockerfile` & `Dockerfile.prod` for easy CI/CD +- Added `compose.yml` for easy local development and testing with other `Docker` containers e.g `Postgres` database +- Added `.dockerignore` file +- Added `.justfile` for speeding command line productivity +- Added `.env` & `.env.example` files for both frotend and backend diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000..19fecde --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1,9 @@ +.tmp/ +.cache/ +.git/ +.env +build/ +node_modules/ +# Ignoring folders that might be used in starter templates +data/ +backup/ diff --git a/backend/.env.example b/backend/.env.example index ebfc96a..01c7475 100644 --- a/backend/.env.example +++ b/backend/.env.example @@ -5,3 +5,13 @@ API_TOKEN_SALT=tobemodified ADMIN_JWT_SECRET=tobemodified TRANSFER_TOKEN_SALT=tobemodified JWT_SECRET=tobemodified +NODE_ENV="development" + +# Database +DATABASE_CLIENT=postgres +DATABASE_HOST=127.0.0.1 +DATABASE_PORT=5432 +DATABASE_NAME=strapi +DATABASE_USERNAME=strapi +DATABASE_PASSWORD=strapi +DATABASE_SSL=false \ No newline at end of file diff --git a/backend/.justfile b/backend/.justfile new file mode 100644 index 0000000..33c5919 --- /dev/null +++ b/backend/.justfile @@ -0,0 +1,27 @@ +# .justfile + +# Default +default: + just --list + +# Build Docker Image +# docker build \ +# --build-arg NODE_ENV=production \ +# # --build-arg STRAPI_URL=https://api.example.com \ # Uncomment to set the Strapi Server URL +# -t invoice-server:latest \ # Replace with your image name +# -f Dockerfile.prod . +build-image: + docker build --build-arg NODE_ENV=production -t invoice-server:latest -f Dockerfile.prod . + +# Run Docker Container +run-container: + docker run -d -p 1337:1337 --network proxy-net --restart always --name invoice-backend invoice-server:latest + +# Docker compose +run-compose: + docker compose up -d + +# Docker compose down +run-compose-down: + docker compose down + diff --git a/backend/Dockerfile b/backend/Dockerfile new file mode 100644 index 0000000..fdd020f --- /dev/null +++ b/backend/Dockerfile @@ -0,0 +1,19 @@ +FROM node:18.18.2-alpine +# Installing libvips-dev for sharp Compatibility +RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev nasm bash vips-dev git +ARG NODE_ENV=development +ENV NODE_ENV=${NODE_ENV} + +WORKDIR /opt/ +COPY package.json yarn.lock ./ +RUN yarn global add node-gyp +RUN yarn config set network-timeout 600000 -g && yarn install +ENV PATH /opt/node_modules/.bin:$PATH + +WORKDIR /opt/app +COPY . . +RUN chown -R node:node /opt/app +USER node +RUN ["yarn", "build"] +EXPOSE 1337 +CMD ["yarn", "develop"] \ No newline at end of file diff --git a/backend/Dockerfile.prod b/backend/Dockerfile.prod new file mode 100644 index 0000000..aa7a606 --- /dev/null +++ b/backend/Dockerfile.prod @@ -0,0 +1,28 @@ +# Creating multi-stage build for production +FROM node:18.18.2-alpine as build +RUN apk update && apk add --no-cache build-base gcc autoconf automake zlib-dev libpng-dev vips-dev git > /dev/null 2>&1 +ENV NODE_ENV=production + +WORKDIR /opt/ +COPY package.json yarn.lock ./ +RUN yarn global add node-gyp +RUN yarn config set network-timeout 600000 -g && yarn install --production +ENV PATH /opt/node_modules/.bin:$PATH +WORKDIR /opt/app +COPY . . +RUN yarn build + +# Creating final production image +FROM node:18.18.2-alpine +RUN apk add --no-cache vips-dev +ENV NODE_ENV=production +WORKDIR /opt/ +COPY --from=build /opt/node_modules ./node_modules +WORKDIR /opt/app +COPY --from=build /opt/app ./ +ENV PATH /opt/node_modules/.bin:$PATH + +RUN chown -R node:node /opt/app +USER node +EXPOSE 1337 +CMD ["yarn", "start"] \ No newline at end of file diff --git a/backend/package.json b/backend/package.json index b67fa93..8b57d71 100644 --- a/backend/package.json +++ b/backend/package.json @@ -11,11 +11,12 @@ }, "devDependencies": {}, "dependencies": { - "@strapi/strapi": "4.24.1", - "@strapi/plugin-users-permissions": "4.24.1", - "@strapi/plugin-i18n": "4.24.1", "@strapi/plugin-cloud": "4.24.1", + "@strapi/plugin-i18n": "4.24.1", + "@strapi/plugin-users-permissions": "4.24.1", + "@strapi/strapi": "4.24.1", "better-sqlite3": "8.6.0", + "pg": "^8.11.5", "react": "^18.0.0", "react-dom": "^18.0.0", "react-router-dom": "5.3.4", diff --git a/backend/yarn.lock b/backend/yarn.lock index af1170d..61f90e9 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -7399,11 +7399,67 @@ pause@0.0.1: resolved "https://registry.yarnpkg.com/pause/-/pause-0.0.1.tgz#1d408b3fdb76923b9543d96fb4c9dfd535d9cb5d" integrity sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg== +pg-cloudflare@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pg-cloudflare/-/pg-cloudflare-1.1.1.tgz#e6d5833015b170e23ae819e8c5d7eaedb472ca98" + integrity sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q== + pg-connection-string@2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.1.tgz#78c23c21a35dd116f48e12e23c0965e8d9e2cbfb" integrity sha512-w6ZzNu6oMmIzEAYVw+RLK0+nqHPt8K3ZnknKi+g48Ak2pr3dtljJW3o+D/n2zzCG07Zoe9VOX3aiKpj+BN0pjg== +pg-connection-string@^2.6.4: + version "2.6.4" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-2.6.4.tgz#f543862adfa49fa4e14bc8a8892d2a84d754246d" + integrity sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA== + +pg-int8@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pg-int8/-/pg-int8-1.0.1.tgz#943bd463bf5b71b4170115f80f8efc9a0c0eb78c" + integrity sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw== + +pg-pool@^3.6.2: + version "3.6.2" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-3.6.2.tgz#3a592370b8ae3f02a7c8130d245bc02fa2c5f3f2" + integrity sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg== + +pg-protocol@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/pg-protocol/-/pg-protocol-1.6.1.tgz#21333e6d83b01faaebfe7a33a7ad6bfd9ed38cb3" + integrity sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg== + +pg-types@^2.1.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-2.2.0.tgz#2d0250d636454f7cfa3b6ae0382fdfa8063254a3" + integrity sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA== + dependencies: + pg-int8 "1.0.1" + postgres-array "~2.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.4" + postgres-interval "^1.1.0" + +pg@^8.11.5: + version "8.11.5" + resolved "https://registry.yarnpkg.com/pg/-/pg-8.11.5.tgz#e722b0a5f1ed92931c31758ebec3ddf878dd4128" + integrity sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw== + dependencies: + pg-connection-string "^2.6.4" + pg-pool "^3.6.2" + pg-protocol "^1.6.1" + pg-types "^2.1.0" + pgpass "1.x" + optionalDependencies: + pg-cloudflare "^1.1.1" + +pgpass@1.x: + version "1.0.5" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.5.tgz#9b873e4a564bb10fa7a7dbd55312728d422a223d" + integrity sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug== + dependencies: + split2 "^4.1.0" + picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -7500,6 +7556,28 @@ postcss@^8.3.11, postcss@^8.4.32, postcss@^8.4.33: picocolors "^1.0.0" source-map-js "^1.2.0" +postgres-array@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-2.0.0.tgz#48f8fce054fbc69671999329b8834b772652d82e" + integrity sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA== + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + integrity sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w== + +postgres-date@~1.0.4: + version "1.0.7" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.7.tgz#51bc086006005e5061c591cee727f2531bf641a8" + integrity sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q== + +postgres-interval@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.2.0.tgz#b460c82cb1587507788819a06aa0fffdb3544695" + integrity sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ== + dependencies: + xtend "^4.0.0" + prebuild-install@^7.1.1: version "7.1.2" resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-7.1.2.tgz#a5fd9986f5a6251fbc47e1e5c65de71e68c0a056" @@ -8694,6 +8772,11 @@ split-string@^3.0.1, split-string@^3.0.2: dependencies: extend-shallow "^3.0.0" +split2@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/split2/-/split2-4.2.0.tgz#c9c5920904d148bab0b9f67145f245a86aadbfa4" + integrity sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg== + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -9631,7 +9714,7 @@ xdg-basedir@^4.0.0: resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-4.0.0.tgz#4bc8d9984403696225ef83a1573cbbcb4e79db13" integrity sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q== -xtend@~4.0.1: +xtend@^4.0.0, xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== diff --git a/compose.yml b/compose.yml new file mode 100644 index 0000000..e8073ed --- /dev/null +++ b/compose.yml @@ -0,0 +1,75 @@ +services: + frontend: + container_name: invoice-client + build: ./frontend + image: invoice-client:latest + restart: unless-stopped + environment: + - NEXT_PUBLIC_STRAPI_BACKEND_SERVER=${NEXT_PUBLIC_STRAPI_BACKEND_SERVER} + ports: + - "3333:3000" + networks: + - proxy-net + depends_on: + - backend + + backend: + container_name: invoice-server + build: + context: ./backend + dockerfile: Dockerfile.prod + image: invoice-server:latest + restart: unless-stopped + env_file: ./backend/.env + environment: + DATABASE_CLIENT: ${DATABASE_CLIENT} + DATABASE_HOST: ${DATABASE_HOST} + DATABASE_PORT: ${DATABASE_PORT} + DATABASE_NAME: ${DATABASE_NAME} + DATABASE_USERNAME: ${DATABASE_USERNAME} + DATABASE_PASSWORD: ${DATABASE_PASSWORD} + JWT_SECRET: ${JWT_SECRET} + ADMIN_JWT_SECRET: ${ADMIN_JWT_SECRET} + APP_KEYS: ${APP_KEYS} + NODE_ENV: ${NODE_ENV} + volumes: + - ./backend/config:/opt/app/config + - ./backend/src:/opt/app/src + - ./backend/package.json:/opt/package.json + - ./backend/yarn.lock:/opt/yarn.lock + - ./backend/.env:/opt/app/.env + - ./backend/public/uploads:/opt/app/public/uploads + ports: + - "1337:1337" + networks: + - proxy-net + depends_on: + - database + + database: + container_name: invoice-database + platform: linux/amd64 #for platform error on Apple M1 chips + restart: unless-stopped + env_file: ./backend/.env + image: postgres:15.5-alpine + environment: + POSTGRES_USER: ${DATABASE_USERNAME} + POSTGRES_PASSWORD: ${DATABASE_PASSWORD} + POSTGRES_DB: ${DATABASE_NAME} + volumes: + - strapi-data:/var/lib/postgresql/data/ #using a volume + #- ./data:/var/lib/postgresql/data/ # if you want to use a bind folder + + ports: + - "5432:5432" + networks: + - proxy-net + +volumes: + strapi-data: + +networks: + proxy-net: + name: proxy-net + driver: bridge + external: true diff --git a/frontend/.dockerignore b/frontend/.dockerignore new file mode 100644 index 0000000..1baf5bb --- /dev/null +++ b/frontend/.dockerignore @@ -0,0 +1,6 @@ +.tmp/ +.cache/ +.git/ +build/ +node_modules/ + diff --git a/frontend/.env.example b/frontend/.env.example new file mode 100644 index 0000000..b0eec60 --- /dev/null +++ b/frontend/.env.example @@ -0,0 +1 @@ +NEXT_PUBLIC_STRAPI_BACKEND_SERVER="http://localhost:1337" \ No newline at end of file diff --git a/frontend/.justfile b/frontend/.justfile new file mode 100644 index 0000000..98dfdb3 --- /dev/null +++ b/frontend/.justfile @@ -0,0 +1,22 @@ +# .justfile + +# Default +default: + just --list + +# Build Docker Image +build-image: + docker build -t invoice-client:latest . + +# Run Docker Container +run-container: + docker run -d -p 3333:3000 --network proxy-net --restart always --name invoice-client invoice-client:latest + +# Docker compose +run-compose: + docker compose up -d + +# Docker compose down +run-compose-down: + docker compose down + diff --git a/frontend/Dockerfile b/frontend/Dockerfile new file mode 100644 index 0000000..ff29940 --- /dev/null +++ b/frontend/Dockerfile @@ -0,0 +1,8 @@ +FROM node:18.18.2-alpine as build +WORKDIR /app +COPY . . +RUN npm ci --silent +RUN npm run build + +FROM lipanski/docker-static-website:2.3.0 as release +COPY --from=build /app/dist . \ No newline at end of file diff --git a/frontend/next.config.js b/frontend/next.config.js index dafb0c8..4a7fa5d 100644 --- a/frontend/next.config.js +++ b/frontend/next.config.js @@ -1,8 +1,15 @@ /** @type {import('next').NextConfig} */ const nextConfig = { - experimental: { - appDir: true, - }, -} + output: 'export', + + // Optional: Change links `/me` -> `/me/` and emit `/me.html` -> `/me/index.html` + // trailingSlash: true, + + // Optional: Prevent automatic `/me` -> `/me/`, instead preserve `href` + // skipTrailingSlashRedirect: true, + + // Optional: Change the output directory `out` -> `dist` + distDir: 'dist', +}; -module.exports = nextConfig +module.exports = nextConfig \ No newline at end of file diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 842f5ca..b191ba4 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8,7 +8,6 @@ "name": "frontend", "version": "0.1.0", "dependencies": { - "@next/font": "14.2.3", "@types/node": "20.12.8", "@types/react": "18.3.1", "@types/react-dom": "18.3.0", @@ -236,14 +235,6 @@ "glob": "10.3.10" } }, - "node_modules/@next/font": { - "version": "14.2.3", - "resolved": "https://registry.npmjs.org/@next/font/-/font-14.2.3.tgz", - "integrity": "sha512-u35UstQmvl3Yrvv2MOi6RcXMH3xDtmWTXcvkYcC/vCZHLqj/5JQ5UyFRf5saDWxFlZIkEh8HCzwNGoiHIr1/NQ==", - "peerDependencies": { - "next": "*" - } - }, "node_modules/@next/swc-darwin-arm64": { "version": "14.2.3", "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.3.tgz", diff --git a/frontend/package.json b/frontend/package.json index eff5b4a..7dfcf5d 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -9,7 +9,6 @@ "lint": "next lint" }, "dependencies": { - "@next/font": "14.2.3", "@types/node": "20.12.8", "@types/react": "18.3.1", "@types/react-dom": "18.3.0", diff --git a/frontend/src/components/InvoiceForm.tsx b/frontend/src/components/InvoiceForm.tsx index b095974..7bc8bee 100644 --- a/frontend/src/components/InvoiceForm.tsx +++ b/frontend/src/components/InvoiceForm.tsx @@ -11,7 +11,7 @@ interface InvoiceFormProps { interface Invoice { id: number; name: string; - attributes: {}; + attributes?: {}; senderEmail: string; recipientEmail: string; shippingAddress: string; @@ -47,7 +47,7 @@ const InvoiceForm: React.FC = ({ onClose, setInvoices, selecte useEffect(() => { if (selectedInvoice) { - for (const [key, value] of Object.entries(selectedInvoice?.attributes)) { + for (const [key, value] of Object.entries(selectedInvoice?.attributes!)) { dispatch({ field: key, value }); } } else { @@ -76,17 +76,47 @@ const InvoiceForm: React.FC = ({ onClose, setInvoices, selecte if (selectedInvoice) { // Update an existing invoice - const data = await axios.put(`http://localhost:1337/api/invoices/${selectedInvoice.id}`, { - data: { name, senderEmail, recipientEmail, shippingAddress, dueDate, date, invoiceNote, description, qty, rate, total }, - }); + const data = await axios.put( + `${process.env.NEXT_PUBLIC_STRAPI_BACKEND_SERVER}/api/invoices/${selectedInvoice.id}`, + { + data: { + name, + senderEmail, + recipientEmail, + shippingAddress, + dueDate, + date, + invoiceNote, + description, + qty, + rate, + total, + }, + } + ); console.log(data) setInvoices((prev) => prev.map((inv) => (inv.id === selectedInvoice.id ? { ...inv, ...formFields } : inv))); window.location.reload() } else { // Create a new invoice - const { data } = await axios.post('http://localhost:1337/api/invoices', { - data: { name, senderEmail, recipientEmail, shippingAddress, dueDate, date, invoiceNote, description, qty, rate, total }, - }); + const { data } = await axios.post( + `${process.env.NEXT_PUBLIC_STRAPI_BACKEND_SERVER}/api/invoices`, + { + data: { + name, + senderEmail, + recipientEmail, + shippingAddress, + dueDate, + date, + invoiceNote, + description, + qty, + rate, + total, + }, + } + ); console.log(data); setInvoices((prev) => [...prev, data.data]); } @@ -100,25 +130,32 @@ const InvoiceForm: React.FC = ({ onClose, setInvoices, selecte return ( <> -
-
- -
-

{selectedInvoice ? 'Edit Invoice' : 'Create Invoice'}

- -
-
-