diff --git a/.github/workflows/cms-dev.yml b/.github/workflows/cms-dev.yml index cd807d1..6188c51 100644 --- a/.github/workflows/cms-dev.yml +++ b/.github/workflows/cms-dev.yml @@ -30,7 +30,7 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build & push CMS docker images - run: make docker-cms ENVIRONMENT=-dev + run: make docker-cms ENVIRONMENT=-dev NEXT_PUBLIC_SERVER_URL=${{ secrets.DEV_CMS_SERVER_URL }} deploy: needs: build-cms diff --git a/Makefile b/Makefile index 26129e1..2379e7b 100644 --- a/Makefile +++ b/Makefile @@ -18,8 +18,8 @@ docker: ## Build and push landing docker images. make build push build-cms: ## Build utexo CMS docker image. - docker build -f ./cms/Dockerfile -t $(IMAGE_UTEXO_CMS_BACKUP) ./cms && \ - docker build -f ./cms/Dockerfile -t $(IMAGE_UTEXO_CMS_LATEST) ./cms + docker build --build-arg NEXT_PUBLIC_SERVER_URL=$(NEXT_PUBLIC_SERVER_URL) -f ./cms/Dockerfile -t $(IMAGE_UTEXO_CMS_BACKUP) ./cms && \ + docker build --build-arg NEXT_PUBLIC_SERVER_URL=$(NEXT_PUBLIC_SERVER_URL) -f ./cms/Dockerfile -t $(IMAGE_UTEXO_CMS_LATEST) ./cms push-cms: ## Push utexo CMS docker image. docker push $(IMAGE_UTEXO_CMS_BACKUP) && \ diff --git a/cms/.env.example b/cms/.env.example index 32349a9..2ce1a38 100644 --- a/cms/.env.example +++ b/cms/.env.example @@ -1,9 +1,20 @@ # PostgreSQL connection string -DATABASE_URL=postgresql://payload:payload_dev@postgres:5432/payload_cms +DATABASE_URL= # Secret key for Payload (generate a random string for production) -PAYLOAD_SECRET=your-secret-here +PAYLOAD_SECRET= # Initial admin/user credentials SEED_USER_EMAIL= SEED_USER_PASSWORD= + +# SMTP / Email +SMTP_HOST= +SMTP_PORT= +SMTP_USER= +SMTP_PASS= +SMTP_FROM_ADDRESS= +SMTP_DEBUG= + +# Public server URL (used for email links, etc.) +NEXT_PUBLIC_SERVER_URL= diff --git a/cms/Dockerfile b/cms/Dockerfile index c99f5e4..7537a27 100644 --- a/cms/Dockerfile +++ b/cms/Dockerfile @@ -25,7 +25,8 @@ ENV NEXT_TELEMETRY_DISABLED=1 # Dummy env vars for build (real values passed at runtime) ENV DATABASE_URL=postgresql://placeholder:placeholder@localhost:5432/placeholder ENV PAYLOAD_SECRET=placeholder-secret-for-build-only -ENV NEXT_PUBLIC_SERVER_URL=https://cms.dev.utexo.com +ARG NEXT_PUBLIC_SERVER_URL=https://placeholder.example.com +ENV NEXT_PUBLIC_SERVER_URL=$NEXT_PUBLIC_SERVER_URL RUN npm run build diff --git a/cms/package-lock.json b/cms/package-lock.json index cafecd1..a0bf849 100644 --- a/cms/package-lock.json +++ b/cms/package-lock.json @@ -10,6 +10,7 @@ "license": "MIT", "dependencies": { "@payloadcms/db-postgres": "3.84.1", + "@payloadcms/email-nodemailer": "^3.84.1", "@payloadcms/next": "3.84.1", "@payloadcms/richtext-lexical": "3.84.1", "@payloadcms/ui": "3.84.1", @@ -26,6 +27,7 @@ "@playwright/test": "1.58.2", "@testing-library/react": "16.3.0", "@types/node": "22.19.9", + "@types/nodemailer": "^8.0.0", "@types/react": "19.2.14", "@types/react-dom": "19.2.3", "@vitejs/plugin-react": "4.5.2", @@ -3043,6 +3045,30 @@ "payload": "3.84.1" } }, + "node_modules/@payloadcms/email-nodemailer": { + "version": "3.84.1", + "resolved": "https://registry.npmjs.org/@payloadcms/email-nodemailer/-/email-nodemailer-3.84.1.tgz", + "integrity": "sha512-pTXl9dfIoXLpdI2BbK0h64Y9I3RLGOG1QkWokSdCDWr+qkOiRkbO7W8dOEtK6Nh8eIwNOMJLA7Og3x4EbGMPxg==", + "license": "MIT", + "dependencies": { + "nodemailer": "7.0.12" + }, + "engines": { + "node": "^18.20.2 || >=20.9.0" + }, + "peerDependencies": { + "payload": "3.84.1" + } + }, + "node_modules/@payloadcms/email-nodemailer/node_modules/nodemailer": { + "version": "7.0.12", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-7.0.12.tgz", + "integrity": "sha512-H+rnK5bX2Pi/6ms3sN4/jRQvYSMltV6vqup/0SFOrxYYY/qoNvhXPlYq3e+Pm9RFJRwrMGbMIwi81M4dxpomhA==", + "license": "MIT-0", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@payloadcms/graphql": { "version": "3.84.1", "resolved": "https://registry.npmjs.org/@payloadcms/graphql/-/graphql-3.84.1.tgz", @@ -3820,6 +3846,16 @@ "undici-types": "~6.21.0" } }, + "node_modules/@types/nodemailer": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-8.0.0.tgz", + "integrity": "sha512-fyf8jWULsCo0d0BuoQ75i6IeoHs47qcqxWc7yUdUcV0pOZGjUTTOvwdG1PRXUDqN/8A64yQdQdnA2pZgcdi+cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/parse-json": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", diff --git a/cms/package.json b/cms/package.json index 29b5468..52bcde1 100644 --- a/cms/package.json +++ b/cms/package.json @@ -21,6 +21,8 @@ "migrate:create": "payload migrate:create" }, "dependencies": { + "@payloadcms/db-postgres": "3.84.1", + "@payloadcms/email-nodemailer": "^3.84.1", "@payloadcms/next": "3.84.1", "@payloadcms/richtext-lexical": "3.84.1", "@payloadcms/ui": "3.84.1", @@ -31,13 +33,13 @@ "payload": "3.84.1", "react": "19.2.6", "react-dom": "19.2.6", - "sharp": "0.34.2", - "@payloadcms/db-postgres": "3.84.1" + "sharp": "0.34.2" }, "devDependencies": { "@playwright/test": "1.58.2", "@testing-library/react": "16.3.0", "@types/node": "22.19.9", + "@types/nodemailer": "^8.0.0", "@types/react": "19.2.14", "@types/react-dom": "19.2.3", "@vitejs/plugin-react": "4.5.2", diff --git a/cms/src/payload.config.ts b/cms/src/payload.config.ts index b9eb992..1b48b1f 100644 --- a/cms/src/payload.config.ts +++ b/cms/src/payload.config.ts @@ -4,6 +4,7 @@ import path from 'path' import { buildConfig } from 'payload' import { fileURLToPath } from 'url' import sharp from 'sharp' +import { nodemailerAdapter } from '@payloadcms/email-nodemailer' import { Users } from './collections/Users' import { Media } from './collections/Media' @@ -15,6 +16,7 @@ const filename = fileURLToPath(import.meta.url) const dirname = path.dirname(filename) export default buildConfig({ + serverURL: process.env.NEXT_PUBLIC_SERVER_URL, cors: ['https://dev.utexo.com', 'https://utexo.com'], admin: { user: Users.slug, @@ -52,4 +54,21 @@ export default buildConfig({ }), sharp, plugins: [], + email: nodemailerAdapter({ + defaultFromAddress: process.env.SMTP_FROM_ADDRESS || 'email-collector@utexo.com', + defaultFromName: 'Utexo CMS', + + transportOptions: { + host: process.env.SMTP_HOST, + port: Number(process.env.SMTP_PORT), + secure: false, + + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASS, + }, + logger: process.env.SMTP_DEBUG === 'true', + debug: process.env.SMTP_DEBUG === 'true', + }, + }), }) diff --git a/new-branding/src/components/common/Navigation/index.tsx b/new-branding/src/components/common/Navigation/index.tsx index 648a3a1..db9c5bf 100644 --- a/new-branding/src/components/common/Navigation/index.tsx +++ b/new-branding/src/components/common/Navigation/index.tsx @@ -16,7 +16,7 @@ export class NavigationItem { public submenu?: NavigationItem[], ) {} } -export const additionalNavigation: NavigationItem[] = [new NavigationItem("Contact", "/contact-sales"), new NavigationItem("Mint USDT", "/mint")]; +export const additionalNavigation: NavigationItem[] = [new NavigationItem("Mint USDT", "/mint"), new NavigationItem("Blog", "/blog"), new NavigationItem("Contact", "/contact-sales")]; const FOCUSABLE_SELECTOR = 'a[href], button:not([disabled]), input:not([disabled]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"])';