Skip to content

Commit 9e2e03e

Browse files
committed
feat: implement product store with checkout, purchase tracking, and download link management
1 parent 4fb64a2 commit 9e2e03e

25 files changed

Lines changed: 1536 additions & 191 deletions

File tree

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"README.md": "${capture}.md",
2929
".eslintrc.json": ".eslintcache, .eslintignore",
3030
".prettierrc.json": ".prettierignore",
31-
"package.json": "package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lockb"
31+
"package.json": "package-lock.json, yarn.lock, pnpm-lock.yaml, bun.lock"
3232
},
3333
"editor.wordWrap": "on"
3434
}

bun.lock

Lines changed: 83 additions & 64 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
"bcryptjs": "^2.4.3",
7575
"class-variance-authority": "^0.7.1",
7676
"clsx": "^2.1.1",
77+
"date-fns": "^4.4.0",
7778
"framer-motion": "^12.40.0",
7879
"isomorphic-dompurify": "^2.22.0",
7980
"jose": "^6.2.3",
Lines changed: 316 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
-- CreateEnum
2+
CREATE TYPE "InquiryStatus" AS ENUM ('NEW', 'IN_PROGRESS', 'CLOSED');
3+
4+
-- CreateEnum
5+
CREATE TYPE "EstimatorLeadStatus" AS ENUM ('NEW', 'CONTACTED', 'CONVERTED', 'CLOSED');
6+
7+
-- CreateEnum
8+
CREATE TYPE "SiteSectionKey" AS ENUM ('HERO', 'ABOUT', 'SERVICES_INTRO', 'TEAM_INTRO', 'PORTFOLIO_INTRO', 'TESTIMONIALS_INTRO', 'CTA', 'CONTACT', 'FOOTER', 'SEO');
9+
10+
-- CreateTable
11+
CREATE TABLE "users" (
12+
"id" UUID NOT NULL,
13+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
14+
"updatedAt" TIMESTAMP(3) NOT NULL,
15+
"email" TEXT NOT NULL,
16+
"hashedPassword" TEXT NOT NULL,
17+
"firstName" TEXT,
18+
"lastName" TEXT,
19+
"isActive" BOOLEAN NOT NULL DEFAULT true,
20+
21+
CONSTRAINT "users_pkey" PRIMARY KEY ("id")
22+
);
23+
24+
-- CreateTable
25+
CREATE TABLE "contact_submissions" (
26+
"id" TEXT NOT NULL,
27+
"name" TEXT NOT NULL,
28+
"email" TEXT NOT NULL,
29+
"message" TEXT NOT NULL,
30+
"isRead" BOOLEAN NOT NULL DEFAULT false,
31+
"status" "InquiryStatus" NOT NULL DEFAULT 'NEW',
32+
"internalNotes" TEXT,
33+
"source" TEXT NOT NULL DEFAULT 'contact',
34+
"estimatorLeadId" TEXT,
35+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
36+
"updatedAt" TIMESTAMP(3) NOT NULL,
37+
38+
CONSTRAINT "contact_submissions_pkey" PRIMARY KEY ("id")
39+
);
40+
41+
-- CreateTable
42+
CREATE TABLE "estimator_leads" (
43+
"id" TEXT NOT NULL,
44+
"projectType" TEXT NOT NULL,
45+
"designApproach" TEXT,
46+
"platform" TEXT,
47+
"scope" TEXT NOT NULL,
48+
"complexity" TEXT NOT NULL,
49+
"timeline" TEXT NOT NULL,
50+
"budgetUsd" DOUBLE PRECISION NOT NULL,
51+
"budgetDisplay" TEXT NOT NULL,
52+
"excludedDeliverables" JSONB,
53+
"deliverableSavingsUsd" DOUBLE PRECISION,
54+
"currency" TEXT NOT NULL DEFAULT 'USD',
55+
"status" "EstimatorLeadStatus" NOT NULL DEFAULT 'NEW',
56+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
57+
"updatedAt" TIMESTAMP(3) NOT NULL,
58+
59+
CONSTRAINT "estimator_leads_pkey" PRIMARY KEY ("id")
60+
);
61+
62+
-- CreateTable
63+
CREATE TABLE "testimonials" (
64+
"id" TEXT NOT NULL,
65+
"clientName" TEXT NOT NULL,
66+
"clientRole" TEXT NOT NULL,
67+
"company" TEXT NOT NULL,
68+
"content" TEXT NOT NULL,
69+
"avatarUrl" TEXT,
70+
"isVisible" BOOLEAN NOT NULL DEFAULT true,
71+
"order" INTEGER NOT NULL DEFAULT 0,
72+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
73+
"updatedAt" TIMESTAMP(3) NOT NULL,
74+
75+
CONSTRAINT "testimonials_pkey" PRIMARY KEY ("id")
76+
);
77+
78+
-- CreateTable
79+
CREATE TABLE "projects" (
80+
"id" TEXT NOT NULL,
81+
"title" TEXT NOT NULL,
82+
"slug" TEXT NOT NULL,
83+
"description" TEXT NOT NULL,
84+
"content" TEXT,
85+
"category" TEXT NOT NULL,
86+
"imageUrl" TEXT NOT NULL,
87+
"liveUrl" TEXT,
88+
"githubUrl" TEXT,
89+
"isFeatured" BOOLEAN NOT NULL DEFAULT false,
90+
"isVisible" BOOLEAN NOT NULL DEFAULT true,
91+
"featuredOrder" INTEGER NOT NULL DEFAULT 0,
92+
"completedAt" TIMESTAMP(3),
93+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
94+
"updatedAt" TIMESTAMP(3) NOT NULL,
95+
96+
CONSTRAINT "projects_pkey" PRIMARY KEY ("id")
97+
);
98+
99+
-- CreateTable
100+
CREATE TABLE "project_tech_stacks" (
101+
"id" TEXT NOT NULL,
102+
"name" TEXT NOT NULL,
103+
"projectId" TEXT NOT NULL,
104+
105+
CONSTRAINT "project_tech_stacks_pkey" PRIMARY KEY ("id")
106+
);
107+
108+
-- CreateTable
109+
CREATE TABLE "project_developers" (
110+
"id" TEXT NOT NULL,
111+
"name" TEXT NOT NULL,
112+
"role" TEXT,
113+
"projectId" TEXT NOT NULL,
114+
115+
CONSTRAINT "project_developers_pkey" PRIMARY KEY ("id")
116+
);
117+
118+
-- CreateTable
119+
CREATE TABLE "site_settings" (
120+
"id" TEXT NOT NULL DEFAULT 'default',
121+
"notificationEmail" TEXT,
122+
"siteName" TEXT,
123+
"siteUrl" TEXT,
124+
"metaDescription" TEXT,
125+
"socialLinks" JSONB,
126+
"maintenanceMode" BOOLEAN NOT NULL DEFAULT false,
127+
"maintenanceMessage" TEXT,
128+
"updatedAt" TIMESTAMP(3) NOT NULL,
129+
130+
CONSTRAINT "site_settings_pkey" PRIMARY KEY ("id")
131+
);
132+
133+
-- CreateTable
134+
CREATE TABLE "faq_items" (
135+
"id" TEXT NOT NULL,
136+
"question" TEXT NOT NULL,
137+
"answer" TEXT NOT NULL,
138+
"order" INTEGER NOT NULL DEFAULT 0,
139+
"isVisible" BOOLEAN NOT NULL DEFAULT true,
140+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
141+
"updatedAt" TIMESTAMP(3) NOT NULL,
142+
143+
CONSTRAINT "faq_items_pkey" PRIMARY KEY ("id")
144+
);
145+
146+
-- CreateTable
147+
CREATE TABLE "service_items" (
148+
"id" TEXT NOT NULL,
149+
"title" TEXT NOT NULL,
150+
"description" TEXT NOT NULL,
151+
"order" INTEGER NOT NULL DEFAULT 0,
152+
"isVisible" BOOLEAN NOT NULL DEFAULT true,
153+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
154+
"updatedAt" TIMESTAMP(3) NOT NULL,
155+
156+
CONSTRAINT "service_items_pkey" PRIMARY KEY ("id")
157+
);
158+
159+
-- CreateTable
160+
CREATE TABLE "team_members" (
161+
"id" TEXT NOT NULL,
162+
"name" TEXT NOT NULL,
163+
"title" TEXT NOT NULL,
164+
"description" TEXT NOT NULL,
165+
"imageUrl" TEXT NOT NULL,
166+
"socialLinks" JSONB,
167+
"order" INTEGER NOT NULL DEFAULT 0,
168+
"isVisible" BOOLEAN NOT NULL DEFAULT true,
169+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
170+
"updatedAt" TIMESTAMP(3) NOT NULL,
171+
172+
CONSTRAINT "team_members_pkey" PRIMARY KEY ("id")
173+
);
174+
175+
-- CreateTable
176+
CREATE TABLE "site_sections" (
177+
"id" TEXT NOT NULL,
178+
"key" "SiteSectionKey" NOT NULL,
179+
"content" JSONB NOT NULL,
180+
"updatedAt" TIMESTAMP(3) NOT NULL,
181+
182+
CONSTRAINT "site_sections_pkey" PRIMARY KEY ("id")
183+
);
184+
185+
-- CreateTable
186+
CREATE TABLE "media_assets" (
187+
"id" TEXT NOT NULL,
188+
"bucket" TEXT NOT NULL,
189+
"path" TEXT NOT NULL,
190+
"publicUrl" TEXT NOT NULL,
191+
"filename" TEXT NOT NULL,
192+
"mimeType" TEXT NOT NULL,
193+
"sizeBytes" INTEGER NOT NULL,
194+
"alt" TEXT,
195+
"uploadedById" UUID,
196+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
197+
198+
CONSTRAINT "media_assets_pkey" PRIMARY KEY ("id")
199+
);
200+
201+
-- CreateTable
202+
CREATE TABLE "activity_logs" (
203+
"id" TEXT NOT NULL,
204+
"actorId" UUID,
205+
"actorEmail" TEXT NOT NULL,
206+
"action" TEXT NOT NULL,
207+
"entityType" TEXT NOT NULL,
208+
"entityId" TEXT,
209+
"metadata" JSONB,
210+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
211+
212+
CONSTRAINT "activity_logs_pkey" PRIMARY KEY ("id")
213+
);
214+
215+
-- CreateTable
216+
CREATE TABLE "products" (
217+
"id" TEXT NOT NULL,
218+
"name" TEXT NOT NULL,
219+
"slug" TEXT NOT NULL,
220+
"description" TEXT NOT NULL,
221+
"price" DOUBLE PRECISION NOT NULL,
222+
"fileKey" TEXT NOT NULL,
223+
"previewUrl" TEXT,
224+
"isVisible" BOOLEAN NOT NULL DEFAULT true,
225+
"order" INTEGER NOT NULL DEFAULT 0,
226+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
227+
"updatedAt" TIMESTAMP(3) NOT NULL,
228+
229+
CONSTRAINT "products_pkey" PRIMARY KEY ("id")
230+
);
231+
232+
-- CreateTable
233+
CREATE TABLE "purchases" (
234+
"id" TEXT NOT NULL,
235+
"productId" TEXT NOT NULL,
236+
"buyerName" TEXT NOT NULL,
237+
"buyerEmail" TEXT NOT NULL,
238+
"downloadToken" TEXT NOT NULL,
239+
"tokenUsed" BOOLEAN NOT NULL DEFAULT false,
240+
"tokenExpiresAt" TIMESTAMP(3) NOT NULL,
241+
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
242+
243+
CONSTRAINT "purchases_pkey" PRIMARY KEY ("id")
244+
);
245+
246+
-- CreateIndex
247+
CREATE UNIQUE INDEX "users_email_key" ON "users"("email");
248+
249+
-- CreateIndex
250+
CREATE UNIQUE INDEX "contact_submissions_estimatorLeadId_key" ON "contact_submissions"("estimatorLeadId");
251+
252+
-- CreateIndex
253+
CREATE INDEX "contact_submissions_status_idx" ON "contact_submissions"("status");
254+
255+
-- CreateIndex
256+
CREATE INDEX "contact_submissions_source_idx" ON "contact_submissions"("source");
257+
258+
-- CreateIndex
259+
CREATE INDEX "estimator_leads_status_idx" ON "estimator_leads"("status");
260+
261+
-- CreateIndex
262+
CREATE INDEX "testimonials_isVisible_idx" ON "testimonials"("isVisible");
263+
264+
-- CreateIndex
265+
CREATE UNIQUE INDEX "projects_slug_key" ON "projects"("slug");
266+
267+
-- CreateIndex
268+
CREATE INDEX "projects_isVisible_idx" ON "projects"("isVisible");
269+
270+
-- CreateIndex
271+
CREATE INDEX "projects_isFeatured_idx" ON "projects"("isFeatured");
272+
273+
-- CreateIndex
274+
CREATE INDEX "projects_featuredOrder_idx" ON "projects"("featuredOrder");
275+
276+
-- CreateIndex
277+
CREATE INDEX "project_tech_stacks_projectId_idx" ON "project_tech_stacks"("projectId");
278+
279+
-- CreateIndex
280+
CREATE UNIQUE INDEX "project_tech_stacks_projectId_name_key" ON "project_tech_stacks"("projectId", "name");
281+
282+
-- CreateIndex
283+
CREATE INDEX "project_developers_projectId_idx" ON "project_developers"("projectId");
284+
285+
-- CreateIndex
286+
CREATE UNIQUE INDEX "project_developers_projectId_name_key" ON "project_developers"("projectId", "name");
287+
288+
-- CreateIndex
289+
CREATE INDEX "faq_items_isVisible_idx" ON "faq_items"("isVisible");
290+
291+
-- CreateIndex
292+
CREATE INDEX "service_items_isVisible_idx" ON "service_items"("isVisible");
293+
294+
-- CreateIndex
295+
CREATE INDEX "team_members_isVisible_idx" ON "team_members"("isVisible");
296+
297+
-- CreateIndex
298+
CREATE UNIQUE INDEX "site_sections_key_key" ON "site_sections"("key");
299+
300+
-- CreateIndex
301+
CREATE INDEX "media_assets_createdAt_idx" ON "media_assets"("createdAt");
302+
303+
-- CreateIndex
304+
CREATE INDEX "media_assets_bucket_idx" ON "media_assets"("bucket");
305+
306+
-- CreateIndex
307+
CREATE INDEX "activity_logs_createdAt_idx" ON "activity_logs"("createdAt");
308+
309+
-- CreateIndex
310+
CREATE INDEX "activity_logs_entityType_entityId_idx" ON "activity_logs"("entityType", "entityId");
311+
312+
-- CreateIndex
313+
CREATE UNIQUE INDEX "products_slug_key" ON "products"("slug");
314+
315+
-- CreateIndex
316+
CREATE UNIQUE INDEX "purchases_downloadToken_key" ON "purchases"("downloadToken");
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
-- CreateIndex
2+
CREATE INDEX "activity_logs_actorId_idx" ON "activity_logs"("actorId");
3+
4+
-- CreateIndex
5+
CREATE INDEX "media_assets_uploadedById_idx" ON "media_assets"("uploadedById");
6+
7+
-- CreateIndex
8+
CREATE INDEX "purchases_productId_idx" ON "purchases"("productId");
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Please do not edit this file manually
2+
# It should be added in your version-control system (e.g., Git)
3+
provider = "postgresql"

0 commit comments

Comments
 (0)