diff --git a/Dockerfile b/Dockerfile index 4cbf16b..298d5e2 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,36 +1,26 @@ -FROM node:20-slim AS base +FROM node:20-slim AS deps WORKDIR /app ENV NEXT_TELEMETRY_DISABLED=1 -FROM base AS deps -WORKDIR /app - COPY package.json package-lock.json ./ -COPY prisma ./prisma RUN npm ci -FROM base AS builder +FROM node:20-slim AS builder +WORKDIR /app + +ENV NEXT_TELEMETRY_DISABLED=1 COPY --from=deps /app/node_modules ./node_modules -COPY --from=deps /app/prisma ./prisma COPY . . -RUN npx next build +RUN npm run build -FROM base AS runner +FROM nginx:alpine AS runner -ENV NODE_ENV=production -ENV PORT=3000 -ENV HOSTNAME=0.0.0.0 - -COPY --from=builder /app/package.json ./package.json -COPY --from=builder /app/node_modules ./node_modules -COPY --from=builder /app/.next ./.next -COPY --from=builder /app/public ./public -COPY --from=builder /app/prisma ./prisma -COPY --from=builder /app/next.config.mjs ./next.config.mjs +COPY --from=builder /app/out /usr/share/nginx/html +RUN sed -i 's/listen 80;/listen 3000;/' /etc/nginx/conf.d/default.conf EXPOSE 3000 -CMD ["sh", "-c", "npx prisma migrate deploy && npm run start"] +CMD ["nginx", "-g", "daemon off;"] diff --git a/next.config.mjs b/next.config.mjs index 4678774..893fef6 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,4 +1,6 @@ /** @type {import('next').NextConfig} */ -const nextConfig = {}; +const nextConfig = { + output: "export" +}; export default nextConfig; diff --git a/package-lock.json b/package-lock.json index 74cf28d..eec0fe9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,13 +8,10 @@ "name": "ghasempour-website", "version": "0.1.0", "dependencies": { - "@prisma/client": "^5.22.0", - "bcryptjs": "^2.4.3", "clsx": "^2.1.1", "gsap": "^3.12.5", "lucide-react": "^0.453.0", "next": "^14.2.30", - "next-auth": "^5.0.0-beta.25", "react": "^18.3.1", "react-dom": "^18.3.1", "zod": "^3.23.8" @@ -27,9 +24,7 @@ "eslint": "^8.57.1", "eslint-config-next": "^14.2.30", "postcss": "^8.4.49", - "prisma": "^5.22.0", "tailwindcss": "^3.4.14", - "tsx": "^4.19.2", "typescript": "^5.6.3" } }, @@ -46,35 +41,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@auth/core": { - "version": "0.41.2", - "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.41.2.tgz", - "integrity": "sha512-Hx5MNBxN2fJTbJKGUKAA0wca43D0Akl3TvufY54Gn8lop7F+34vU1zA1pn0vQfIoVuLIrpfc2nkyjwIaPJMW7w==", - "license": "ISC", - "dependencies": { - "@panva/hkdf": "^1.2.1", - "jose": "^6.0.6", - "oauth4webapi": "^3.3.0", - "preact": "10.24.3", - "preact-render-to-string": "6.5.11" - }, - "peerDependencies": { - "@simplewebauthn/browser": "^9.0.1", - "@simplewebauthn/server": "^9.0.2", - "nodemailer": "^7.0.7" - }, - "peerDependenciesMeta": { - "@simplewebauthn/browser": { - "optional": true - }, - "@simplewebauthn/server": { - "optional": true - }, - "nodemailer": { - "optional": true - } - } - }, "node_modules/@emnapi/core": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", @@ -109,448 +75,6 @@ "tslib": "^2.4.0" } }, - "node_modules/@esbuild/aix-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.0.tgz", - "integrity": "sha512-lhRUCeuOyJQURhTxl4WkpFTjIsbDayJHih5kZC1giwE+MhIzAb7mEsQMqMf18rHLsrb5qI1tafG20mLxEWcWlA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.0.tgz", - "integrity": "sha512-wqh0ByljabXLKHeWXYLqoJ5jKC4XBaw6Hk08OfMrCRd2nP2ZQ5eleDZC41XHyCNgktBGYMbqnrJKq/K/lzPMSQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.0.tgz", - "integrity": "sha512-+WzIXQOSaGs33tLEgYPYe/yQHf0WTU0X42Jca3y8NWMbUVhp7rUnw+vAsRC/QiDrdD31IszMrZy+qwPOPjd+rw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.0.tgz", - "integrity": "sha512-+VJggoaKhk2VNNqVL7f6S189UzShHC/mR9EE8rDdSkdpN0KflSwWY/gWjDrNxxisg8Fp1ZCD9jLMo4m0OUfeUA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.0.tgz", - "integrity": "sha512-0T+A9WZm+bZ84nZBtk1ckYsOvyA3x7e2Acj1KdVfV4/2tdG4fzUp91YHx+GArWLtwqp77pBXVCPn2We7Letr0Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.0.tgz", - "integrity": "sha512-fyzLm/DLDl/84OCfp2f/XQ4flmORsjU7VKt8HLjvIXChJoFFOIL6pLJPH4Yhd1n1gGFF9mPwtlN5Wf82DZs+LQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.0.tgz", - "integrity": "sha512-l9GeW5UZBT9k9brBYI+0WDffcRxgHQD8ShN2Ur4xWq/NFzUKm3k5lsH4PdaRgb2w7mI9u61nr2gI2mLI27Nh3Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.0.tgz", - "integrity": "sha512-BXoQai/A0wPO6Es3yFJ7APCiKGc1tdAEOgeTNy3SsB491S3aHn4S4r3e976eUnPdU+NbdtmBuLncYir2tMU9Nw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.0.tgz", - "integrity": "sha512-CjaaREJagqJp7iTaNQjjidaNbCKYcd4IDkzbwwxtSvjI7NZm79qiHc8HqciMddQ6CKvJT6aBd8lO9kN/ZudLlw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.0.tgz", - "integrity": "sha512-RVyzfb3FWsGA55n6WY0MEIEPURL1FcbhFE6BffZEMEekfCzCIMtB5yyDcFnVbTnwk+CLAgTujmV/Lgvih56W+A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.0.tgz", - "integrity": "sha512-KBnSTt1kxl9x70q+ydterVdl+Cn0H18ngRMRCEQfrbqdUuntQQ0LoMZv47uB97NljZFzY6HcfqEZ2SAyIUTQBQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.0.tgz", - "integrity": "sha512-zpSlUce1mnxzgBADvxKXX5sl8aYQHo2ezvMNI8I0lbblJtp8V4odlm3Yzlj7gPyt3T8ReksE6bK+pT3WD+aJRg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.0.tgz", - "integrity": "sha512-2jIfP6mmjkdmeTlsX/9vmdmhBmKADrWqN7zcdtHIeNSCH1SqIoNI63cYsjQR8J+wGa4Y5izRcSHSm8K3QWmk3w==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.0.tgz", - "integrity": "sha512-bc0FE9wWeC0WBm49IQMPSPILRocGTQt3j5KPCA8os6VprfuJ7KD+5PzESSrJ6GmPIPJK965ZJHTUlSA6GNYEhg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.0.tgz", - "integrity": "sha512-SQPZOwoTTT/HXFXQJG/vBX8sOFagGqvZyXcgLA3NhIqcBv1BJU1d46c0rGcrij2B56Z2rNiSLaZOYW5cUk7yLQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.0.tgz", - "integrity": "sha512-SCfR0HN8CEEjnYnySJTd2cw0k9OHB/YFzt5zgJEwa+wL/T/raGWYMBqwDNAC6dqFKmJYZoQBRfHjgwLHGSrn3Q==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.0.tgz", - "integrity": "sha512-us0dSb9iFxIi8srnpl931Nvs65it/Jd2a2K3qs7fz2WfGPHqzfzZTfec7oxZJRNPXPnNYZtanmRc4AL/JwVzHQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.0.tgz", - "integrity": "sha512-CR/RYotgtCKwtftMwJlUU7xCVNg3lMYZ0RzTmAHSfLCXw3NtZtNpswLEj/Kkf6kEL3Gw+BpOekRX0BYCtklhUw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.0.tgz", - "integrity": "sha512-nU1yhmYutL+fQ71Kxnhg8uEOdC0pwEW9entHykTgEbna2pw2dkbFSMeqjjyHZoCmt8SBkOSvV+yNmm94aUrrqw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.0.tgz", - "integrity": "sha512-cXb5vApOsRsxsEl4mcZ1XY3D4DzcoMxR/nnc4IyqYs0rTI8ZKmW6kyyg+11Z8yvgMfAEldKzP7AdP64HnSC/6g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.0.tgz", - "integrity": "sha512-8wZM2qqtv9UP3mzy7HiGYNH/zjTA355mpeuA+859TyR+e+Tc08IHYpLJuMsfpDJwoLo1ikIJI8jC3GFjnRClzA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.0.tgz", - "integrity": "sha512-FLGfyizszcef5C3YtoyQDACyg95+dndv79i2EekILBofh5wpCa1KuBqOWKrEHZg3zrL3t5ouE5jgr94vA+Wb2w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.0.tgz", - "integrity": "sha512-1ZgjUoEdHZZl/YlV76TSCz9Hqj9h9YmMGAgAPYd+q4SicWNX3G5GCyx9uhQWSLcbvPW8Ni7lj4gDa1T40akdlw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.0.tgz", - "integrity": "sha512-Q9StnDmQ/enxnpxCCLSg0oo4+34B9TdXpuyPeTedN/6+iXBJ4J+zwfQI28u/Jl40nOYAxGoNi7mFP40RUtkmUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.0.tgz", - "integrity": "sha512-zF3ag/gfiCe6U2iczcRzSYJKH1DCI+ByzSENHlM2FcDbEeo5Zd2C86Aq0tKUYAJJ1obRP84ymxIAksZUcdztHA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.0.tgz", - "integrity": "sha512-pEl1bO9mfAmIC+tW5btTmrKaujg3zGtUmWNdCw/xs70FBjwAL3o9OEKNHvNmnyylD6ubxUERiEhdsL0xBQ9efw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", @@ -959,15 +483,6 @@ "node": ">=12.4.0" } }, - "node_modules/@panva/hkdf": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz", - "integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/@pkgjs/parseargs": { "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", @@ -979,74 +494,6 @@ "node": ">=14" } }, - "node_modules/@prisma/client": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.22.0.tgz", - "integrity": "sha512-M0SVXfyHnQREBKxCgyo7sffrKttwE6R8PMq330MIUF0pTwjUhLbW84pFDlf06B27XyCR++VtjugEnIHdr07SVA==", - "hasInstallScript": true, - "license": "Apache-2.0", - "engines": { - "node": ">=16.13" - }, - "peerDependencies": { - "prisma": "*" - }, - "peerDependenciesMeta": { - "prisma": { - "optional": true - } - } - }, - "node_modules/@prisma/debug": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.22.0.tgz", - "integrity": "sha512-AUt44v3YJeggO2ZU5BkXI7M4hu9BF2zzH2iF2V5pyXT/lRTyWiElZ7It+bRH1EshoMRxHgpYg4VB6rCM+mG5jQ==", - "devOptional": true, - "license": "Apache-2.0" - }, - "node_modules/@prisma/engines": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.22.0.tgz", - "integrity": "sha512-UNjfslWhAt06kVL3CjkuYpHAWSO6L4kDCVPegV6itt7nD1kSJavd3vhgAEhjglLJJKEdJ7oIqDJ+yHk6qO8gPA==", - "devOptional": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@prisma/debug": "5.22.0", - "@prisma/engines-version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2", - "@prisma/fetch-engine": "5.22.0", - "@prisma/get-platform": "5.22.0" - } - }, - "node_modules/@prisma/engines-version": { - "version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2.tgz", - "integrity": "sha512-2PTmxFR2yHW/eB3uqWtcgRcgAbG1rwG9ZriSvQw+nnb7c4uCr3RAcGMb6/zfE88SKlC1Nj2ziUvc96Z379mHgQ==", - "devOptional": true, - "license": "Apache-2.0" - }, - "node_modules/@prisma/fetch-engine": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.22.0.tgz", - "integrity": "sha512-bkrD/Mc2fSvkQBV5EpoFcZ87AvOgDxbG99488a5cexp5Ccny+UM6MAe/UFkUC0wLYD9+9befNOqGiIJhhq+HbA==", - "devOptional": true, - "license": "Apache-2.0", - "dependencies": { - "@prisma/debug": "5.22.0", - "@prisma/engines-version": "5.22.0-44.605197351a3c8bdd595af2d2a9bc3025bca48ea2", - "@prisma/get-platform": "5.22.0" - } - }, - "node_modules/@prisma/get-platform": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.22.0.tgz", - "integrity": "sha512-pHhpQdr1UPFpt+zFfnPazhulaZYCUqeIcPpJViYoq9R+D/yw4fjE+CtnsnKzPYm0ddUbeXUzjGVGIRVgPDCk4Q==", - "devOptional": true, - "license": "Apache-2.0", - "dependencies": { - "@prisma/debug": "5.22.0" - } - }, "node_modules/@rtsao/scc": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", @@ -2072,12 +1519,6 @@ "node": ">=6.0.0" } }, - "node_modules/bcryptjs": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/bcryptjs/-/bcryptjs-2.4.3.tgz", - "integrity": "sha512-V/Hy/X9Vt7f3BbPJEi8BdVFMByHi+jNXrYkW3huaybV/kQ0KJg0Y6PkEMbn+zeT+i+SiKZ/HMqJGIIt4LZDqNQ==", - "license": "MIT" - }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -2754,48 +2195,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esbuild": { - "version": "0.28.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.0.tgz", - "integrity": "sha512-sNR9MHpXSUV/XB4zmsFKN+QgVG82Cc7+/aaxJ8Adi8hyOac+EXptIp45QBPaVyX3N70664wRbTcLTOemCAnyqw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.28.0", - "@esbuild/android-arm": "0.28.0", - "@esbuild/android-arm64": "0.28.0", - "@esbuild/android-x64": "0.28.0", - "@esbuild/darwin-arm64": "0.28.0", - "@esbuild/darwin-x64": "0.28.0", - "@esbuild/freebsd-arm64": "0.28.0", - "@esbuild/freebsd-x64": "0.28.0", - "@esbuild/linux-arm": "0.28.0", - "@esbuild/linux-arm64": "0.28.0", - "@esbuild/linux-ia32": "0.28.0", - "@esbuild/linux-loong64": "0.28.0", - "@esbuild/linux-mips64el": "0.28.0", - "@esbuild/linux-ppc64": "0.28.0", - "@esbuild/linux-riscv64": "0.28.0", - "@esbuild/linux-s390x": "0.28.0", - "@esbuild/linux-x64": "0.28.0", - "@esbuild/netbsd-arm64": "0.28.0", - "@esbuild/netbsd-x64": "0.28.0", - "@esbuild/openbsd-arm64": "0.28.0", - "@esbuild/openbsd-x64": "0.28.0", - "@esbuild/openharmony-arm64": "0.28.0", - "@esbuild/sunos-x64": "0.28.0", - "@esbuild/win32-arm64": "0.28.0", - "@esbuild/win32-ia32": "0.28.0", - "@esbuild/win32-x64": "0.28.0" - } - }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -4354,15 +3753,6 @@ "jiti": "bin/jiti.js" } }, - "node_modules/jose": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.3.tgz", - "integrity": "sha512-YYVDInQKFJfR/xa3ojUTl8c2KoTwiL1R5Wg9YCydwH0x0B9grbzlg5HC7mMjCtUJjbQ/YnGEZIhI5tCgfTb4Hw==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -4724,33 +4114,6 @@ } } }, - "node_modules/next-auth": { - "version": "5.0.0-beta.31", - "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-5.0.0-beta.31.tgz", - "integrity": "sha512-1OBgCKPzo+S7UWWMp3xgvGvIJ0OpV7B3vR4ZDRqD9a4Ch+OT6dakLXG9ivhtmIWVa71nTSXattOHyCg8sNi8/Q==", - "license": "ISC", - "dependencies": { - "@auth/core": "0.41.2" - }, - "peerDependencies": { - "@simplewebauthn/browser": "^9.0.1", - "@simplewebauthn/server": "^9.0.2", - "next": "^14.0.0-0 || ^15.0.0 || ^16.0.0", - "nodemailer": "^7.0.7", - "react": "^18.2.0 || ^19.0.0" - }, - "peerDependenciesMeta": { - "@simplewebauthn/browser": { - "optional": true - }, - "@simplewebauthn/server": { - "optional": true - }, - "nodemailer": { - "optional": true - } - } - }, "node_modules/next/node_modules/postcss": { "version": "8.4.31", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", @@ -4825,15 +4188,6 @@ "node": ">=0.10.0" } }, - "node_modules/oauth4webapi": { - "version": "3.8.6", - "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.8.6.tgz", - "integrity": "sha512-iwemM91xz8nryHti2yTmg5fhyEMVOkOXwHNqbvcATjyajb5oQxCQzrNOA6uElRHuMhQQTKUyFKV9y/CNyg25BQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/panva" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -5346,25 +4700,6 @@ "dev": true, "license": "MIT" }, - "node_modules/preact": { - "version": "10.24.3", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz", - "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/preact" - } - }, - "node_modules/preact-render-to-string": { - "version": "6.5.11", - "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.5.11.tgz", - "integrity": "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==", - "license": "MIT", - "peerDependencies": { - "preact": ">=10" - } - }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -5375,26 +4710,6 @@ "node": ">= 0.8.0" } }, - "node_modules/prisma": { - "version": "5.22.0", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.22.0.tgz", - "integrity": "sha512-vtpjW3XuYCSnMsNVBjLMNkTj6OZbudcPPTPYHqX0CJfpcdWciI1dM8uHETwmDxxiqEwCIE6WvXucWUetJgfu/A==", - "devOptional": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@prisma/engines": "5.22.0" - }, - "bin": { - "prisma": "build/index.js" - }, - "engines": { - "node": ">=16.13" - }, - "optionalDependencies": { - "fsevents": "2.3.3" - } - }, "node_modules/prop-types": { "version": "15.8.1", "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", @@ -6426,25 +5741,6 @@ "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, - "node_modules/tsx": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.22.1.tgz", - "integrity": "sha512-TvncJykhxAzFCk0VQZKBTClall4Pm7qXDSodb6uxi8QFa8X8mT6ABjxxsQ2opDRYxG7AzcRWXaFtruz5HJKuWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.28.0" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index 7da0b9a..8380d94 100644 --- a/package.json +++ b/package.json @@ -4,21 +4,15 @@ "private": true, "scripts": { "dev": "next dev", - "build": "prisma generate && next build", + "build": "next build", "start": "next start", - "lint": "next lint", - "prisma:generate": "prisma generate", - "prisma:migrate": "prisma migrate dev", - "prisma:seed": "tsx prisma/seed.ts" + "lint": "next lint" }, "dependencies": { - "@prisma/client": "^5.22.0", - "bcryptjs": "^2.4.3", "clsx": "^2.1.1", "gsap": "^3.12.5", "lucide-react": "^0.453.0", "next": "^14.2.30", - "next-auth": "^5.0.0-beta.25", "react": "^18.3.1", "react-dom": "^18.3.1", "zod": "^3.23.8" @@ -31,9 +25,7 @@ "eslint": "^8.57.1", "eslint-config-next": "^14.2.30", "postcss": "^8.4.49", - "prisma": "^5.22.0", "tailwindcss": "^3.4.14", - "tsx": "^4.19.2", "typescript": "^5.6.3" } } diff --git a/prisma/schema.prisma b/prisma/schema.prisma deleted file mode 100644 index f3fbeb8..0000000 --- a/prisma/schema.prisma +++ /dev/null @@ -1,31 +0,0 @@ -generator client { - provider = "prisma-client-js" -} - -datasource db { - provider = "postgresql" - url = env("DATABASE_URL") -} - -enum Role { - SUPERADMIN - ADMIN - EDITOR -} - -model User { - id String @id @default(cuid()) - name String - email String @unique - passwordHash String - role Role @default(EDITOR) - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt -} - -model SiteContent { - id String @id @default("main") - content Json - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt -} diff --git a/prisma/seed.ts b/prisma/seed.ts deleted file mode 100644 index 75ac775..0000000 --- a/prisma/seed.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { PrismaClient, Role } from "@prisma/client"; -import { hashSync } from "bcryptjs"; -import { defaultSiteContent } from "../src/lib/default-content"; - -const prisma = new PrismaClient(); - -async function main() { - await prisma.siteContent.upsert({ - where: { id: "main" }, - update: { content: defaultSiteContent as unknown as object }, - create: { - id: "main", - content: defaultSiteContent as unknown as object - } - }); - - await prisma.user.upsert({ - where: { email: "superadmin@example.com" }, - update: {}, - create: { - name: "Super Admin", - email: "superadmin@example.com", - passwordHash: hashSync("ChangeMe123!", 10), - role: Role.SUPERADMIN - } - }); -} - -main() - .then(async () => { - await prisma.$disconnect(); - }) - .catch(async (error) => { - console.error(error); - await prisma.$disconnect(); - process.exit(1); - }); diff --git a/src/app/api/auth/[...nextauth]/route.ts b/src/app/api/auth/[...nextauth]/route.ts deleted file mode 100644 index c55a45e..0000000 --- a/src/app/api/auth/[...nextauth]/route.ts +++ /dev/null @@ -1,3 +0,0 @@ -import { handlers } from "@/lib/auth"; - -export const { GET, POST } = handlers; diff --git a/src/app/api/sales-requests/route.ts b/src/app/api/sales-requests/route.ts deleted file mode 100644 index e2236aa..0000000 --- a/src/app/api/sales-requests/route.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { NextResponse } from "next/server"; -import { mkdir, readFile, writeFile } from "fs/promises"; -import path from "path"; - -type SalesRequestRecord = { - id: string; - fullName: string; - mobile: string; - brand: string; - description: string; - createdAt: string; -}; - -const storagePath = path.join(process.cwd(), "data", "sales-requests.json"); - -function normalizeMobile(input: string) { - const digits = input.replace(/\D/g, ""); - - if (!digits) { - return ""; - } - - if (digits.startsWith("98")) { - return `0${digits.slice(2)}`; - } - - if (digits.startsWith("9")) { - return `0${digits}`; - } - - if (digits.startsWith("0")) { - return digits; - } - - return `0${digits}`; -} - -async function readRequests() { - try { - const payload = await readFile(storagePath, "utf8"); - const parsed = JSON.parse(payload); - return Array.isArray(parsed) ? (parsed as SalesRequestRecord[]) : []; - } catch { - return []; - } -} - -export async function POST(request: Request) { - try { - const body = (await request.json()) as Partial; - const fullName = (body.fullName ?? "").trim(); - const mobile = normalizeMobile(body.mobile ?? ""); - const brand = (body.brand ?? "").trim(); - const description = (body.description ?? "").trim(); - - if (fullName.length < 3) { - return NextResponse.json({ ok: false, message: "نام و نام خانوادگی معتبر نیست." }, { status: 400 }); - } - - if (!/^09\d{9}$/.test(mobile)) { - return NextResponse.json({ ok: false, message: "شماره موبایل معتبر نیست." }, { status: 400 }); - } - - if (!brand) { - return NextResponse.json({ ok: false, message: "انتخاب برند الزامی است." }, { status: 400 }); - } - - const records = await readRequests(); - const nextRecord: SalesRequestRecord = { - id: crypto.randomUUID(), - fullName, - mobile, - brand, - description, - createdAt: new Date().toISOString() - }; - - await mkdir(path.dirname(storagePath), { recursive: true }); - await writeFile(storagePath, JSON.stringify([nextRecord, ...records], null, 2), "utf8"); - - return NextResponse.json({ - ok: true, - message: "درخواست شما ثبت شد کارشناسان ما تا ساعات اینده با شما تماس میگیرند." - }); - } catch { - return NextResponse.json({ ok: false, message: "ثبت درخواست انجام نشد." }, { status: 500 }); - } -} diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 4c62147..76dfef9 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,23 +1,18 @@ import type { Metadata } from "next"; import "@/app/globals.css"; -import { getSiteContent } from "@/lib/site-content"; +import { defaultSiteContent } from "@/lib/default-content"; -export async function generateMetadata(): Promise { - const content = await getSiteContent(); - return { - title: content.settings.siteTitle, - description: content.hero.description - }; -} +export const metadata: Metadata = { + title: defaultSiteContent.settings.siteTitle, + description: defaultSiteContent.hero.description +}; -export default async function RootLayout({ +export default function RootLayout({ children }: Readonly<{ children: React.ReactNode; }>) { - await getSiteContent(); - return ( {children} diff --git a/src/app/mugmanager/(protected)/layout.tsx b/src/app/mugmanager/(protected)/layout.tsx deleted file mode 100644 index 3d94e26..0000000 --- a/src/app/mugmanager/(protected)/layout.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import { AdminShell } from "@/components/admin/admin-shell"; - -export default function MugmanagerProtectedLayout({ - children -}: { - children: React.ReactNode; -}) { - return {children}; -} diff --git a/src/app/mugmanager/(protected)/page.tsx b/src/app/mugmanager/(protected)/page.tsx deleted file mode 100644 index 611911e..0000000 --- a/src/app/mugmanager/(protected)/page.tsx +++ /dev/null @@ -1,47 +0,0 @@ -import { Dashboard } from "@/components/admin/dashboard"; -import { auth } from "@/lib/auth"; -import { getSiteContent, getUsers } from "@/lib/site-content"; - -export const dynamic = "force-dynamic"; - -const validSections = [ - "overview", - "site-settings", - "homepage", - "brands", - "branches", - "media", - "users" -] as const; - -type ValidSection = (typeof validSections)[number]; - -type SearchParams = { - section?: string; -}; - -export default async function MugmanagerPage({ - searchParams -}: { - searchParams?: SearchParams; -}) { - const [session, content, users] = await Promise.all([ - auth(), - getSiteContent(), - getUsers() - ]); - const requestedSection = searchParams?.section; - const activeSection = - requestedSection && validSections.includes(requestedSection as ValidSection) - ? (requestedSection as ValidSection) - : "overview"; - - return ( - - ); -} diff --git a/src/app/mugmanager/layout.tsx b/src/app/mugmanager/layout.tsx deleted file mode 100644 index 97a019e..0000000 --- a/src/app/mugmanager/layout.tsx +++ /dev/null @@ -1,7 +0,0 @@ -export default function MugmanagerRootLayout({ - children -}: { - children: React.ReactNode; -}) { - return children; -} diff --git a/src/app/mugmanager/login/page.tsx b/src/app/mugmanager/login/page.tsx deleted file mode 100644 index a81da4b..0000000 --- a/src/app/mugmanager/login/page.tsx +++ /dev/null @@ -1,27 +0,0 @@ -import { redirect } from "next/navigation"; - -import { LoginForm } from "@/components/admin/login-form"; -import { auth } from "@/lib/auth"; - -export default async function LoginPage() { - const session = await auth(); - const defaultEmail = process.env.SEED_SUPERADMIN_EMAIL || "superadmin@example.com"; - const defaultPassword = process.env.SEED_SUPERADMIN_PASSWORD || "ChangeMe123!"; - - if (session?.user) { - redirect("/mugmanager"); - } - - return ( -
-
-

ورود به پنل /mugmanager

-

برای مدیریت محتوا و کاربران با حساب ادمین وارد شوید.

- -

- کاربر پیش‌فرض: {defaultEmail} / {defaultPassword} -

-
-
- ); -} diff --git a/src/app/page.tsx b/src/app/page.tsx index e556472..3a39e37 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -1,9 +1,7 @@ import { HomePage } from "@/components/home/home-page"; import { getSiteContent } from "@/lib/site-content"; -export const dynamic = "force-dynamic"; - -export default async function Page() { - const content = await getSiteContent(); +export default function Page() { + const content = getSiteContent(); return ; } diff --git a/src/components/admin/admin-shell.tsx b/src/components/admin/admin-shell.tsx deleted file mode 100644 index 85e63b3..0000000 --- a/src/components/admin/admin-shell.tsx +++ /dev/null @@ -1,60 +0,0 @@ -import Link from "next/link"; -import { redirect } from "next/navigation"; - -import { logoutAction } from "@/lib/actions/admin"; -import { auth } from "@/lib/auth"; - -export async function AdminShell({ children }: { children: React.ReactNode }) { - const session = await auth(); - - if (!session?.user) { - redirect("/mugmanager/login"); - } - - return ( -
-
- - -
{children}
-
-
- ); -} diff --git a/src/components/admin/dashboard.tsx b/src/components/admin/dashboard.tsx deleted file mode 100644 index f8b8e39..0000000 --- a/src/components/admin/dashboard.tsx +++ /dev/null @@ -1,697 +0,0 @@ -import Link from "next/link"; -import { - Blocks, - Building2, - ChevronLeft, - Globe, - Images, - LayoutDashboard, - Settings2, - ShieldCheck, - Sparkles -} from "lucide-react"; - -import { hasRole } from "@/lib/permissions"; -import { - createUserAction, - deleteBranchAction, - deleteBrandAction, - deleteUserAction, - resetContentAction, - updateAutoArshiaAction, - updateBranchesSectionAction, - updateFooterAction, - updateHeroAction, - updateServicesAction, - updateSiteSettingsAction, - updateUserRoleAction, - uploadAssetAction, - upsertBranchAction, - upsertBrandAction -} from "@/lib/actions/admin"; -import { SiteContent, UserRecord } from "@/types/content"; -import { ActionForm } from "@/components/admin/status-message"; - -type AdminSection = - | "overview" - | "site-settings" - | "homepage" - | "brands" - | "branches" - | "media" - | "users"; - -type Props = { - content: SiteContent; - users: UserRecord[]; - currentRole: "SUPERADMIN" | "ADMIN" | "EDITOR"; - activeSection: AdminSection; -}; - -const sectionItems = [ - { id: "overview", label: "نمای کلی", description: "خلاصه وضعیت پنل", icon: LayoutDashboard }, - { id: "site-settings", label: "تنظیمات سایت", description: "هویت برند و اطلاعات کلی", icon: Settings2 }, - { id: "homepage", label: "صفحه اصلی", description: "Hero، خدمات، اتو آرشیا و فوتر", icon: Sparkles }, - { id: "brands", label: "برندها", description: "مدیریت برندها و ترتیب نمایش", icon: Blocks }, - { id: "branches", label: "شعب", description: "تنظیمات نقشه و اطلاعات شعب", icon: Building2 }, - { id: "media", label: "رسانه", description: "آپلود و مدیریت فایل‌ها", icon: Images, minRole: "ADMIN" }, - { id: "users", label: "کاربران", description: "مدیریت دسترسی تیم", icon: ShieldCheck, superadminOnly: true } -] satisfies Array<{ - id: AdminSection; - label: string; - description: string; - icon: React.ComponentType<{ className?: string }>; - superadminOnly?: boolean; - minRole?: Props["currentRole"]; -}>; - -function canAccessSection( - currentRole: Props["currentRole"], - item: { superadminOnly?: boolean; minRole?: Props["currentRole"] } -) { - if (item.superadminOnly) { - return hasRole(currentRole, "SUPERADMIN"); - } - - if (item.minRole) { - return hasRole(currentRole, item.minRole); - } - - return true; -} - -function Field({ - label, - name, - defaultValue, - textarea = false, - type = "text" -}: { - label: string; - name: string; - defaultValue?: string; - textarea?: boolean; - type?: string; -}) { - const baseClassName = - "w-full rounded-2xl border border-white/10 bg-black/30 px-4 py-3 text-sm text-white outline-none transition placeholder:text-gray-500 focus:border-red-500/40 focus:bg-black/50"; - - return ( -