Skip to content

Commit 3845ecd

Browse files
committed
add testimonials
1 parent e17fc3a commit 3845ecd

15 files changed

+1133
-118
lines changed

Dockerfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,4 @@ RUN npm run build
2020
EXPOSE 3000
2121

2222
# Start the application
23-
CMD ["npm", "start"]
23+
CMD ["./run.sh"]

app/components/ui/checkbox.tsx

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as React from "react";
2+
import * as CheckboxPrimitive from "@radix-ui/react-checkbox";
3+
import { Check } from "lucide-react";
4+
import { cn } from "~/lib/utils";
5+
6+
const Checkbox = React.forwardRef<
7+
React.ElementRef<typeof CheckboxPrimitive.Root>,
8+
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>
9+
>(({ className, ...props }, ref) => (
10+
<CheckboxPrimitive.Root
11+
ref={ref}
12+
className={cn(
13+
"peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground",
14+
className
15+
)}
16+
{...props}
17+
>
18+
<CheckboxPrimitive.Indicator
19+
className={cn("flex items-center justify-center text-current")}
20+
>
21+
<Check className="h-4 w-4" />
22+
</CheckboxPrimitive.Indicator>
23+
</CheckboxPrimitive.Root>
24+
));
25+
Checkbox.displayName = CheckboxPrimitive.Root.displayName;
26+
27+
export { Checkbox };

app/data-access/testimonials.ts

+19
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { database } from "~/db";
2+
import {
3+
type Testimonial,
4+
type TestimonialCreate,
5+
testimonials,
6+
} from "~/db/schema";
7+
8+
export async function createTestimonial(data: TestimonialCreate) {
9+
return await database.insert(testimonials).values(data).returning();
10+
}
11+
12+
export async function getTestimonials() {
13+
return await database.query.testimonials.findMany({
14+
with: {
15+
profile: true,
16+
},
17+
orderBy: (testimonials, { desc }) => [desc(testimonials.createdAt)],
18+
});
19+
}

app/db/schema.ts

+32-10
Original file line numberDiff line numberDiff line change
@@ -109,10 +109,40 @@ export const progress = tableCreator(
109109
]
110110
);
111111

112+
export const testimonials = tableCreator("testimonial", {
113+
id: serial("id").primaryKey(),
114+
userId: serial("userId")
115+
.notNull()
116+
.references(() => users.id, { onDelete: "cascade" }),
117+
content: text("content").notNull(),
118+
emojis: text("emojis").notNull(),
119+
displayName: text("displayName").notNull(),
120+
permissionGranted: boolean("permissionGranted").notNull().default(false),
121+
createdAt: timestamp("created_at").notNull().defaultNow(),
122+
updatedAt: timestamp("updated_at").notNull().defaultNow(),
123+
});
124+
125+
export const attachments = tableCreator("attachment", {
126+
id: serial("id").primaryKey(),
127+
segmentId: serial("segmentId")
128+
.notNull()
129+
.references(() => segments.id, { onDelete: "cascade" }),
130+
fileName: text("fileName").notNull(),
131+
fileKey: text("fileKey").notNull(),
132+
createdAt: timestamp("created_at").notNull().defaultNow(),
133+
});
134+
112135
export const modulesRelations = relations(modules, ({ many }) => ({
113136
segments: many(segments),
114137
}));
115138

139+
export const testimonialsRelations = relations(testimonials, ({ one }) => ({
140+
profile: one(profiles, {
141+
fields: [testimonials.userId],
142+
references: [profiles.userId],
143+
}),
144+
}));
145+
116146
export const segmentsRelations = relations(segments, ({ one, many }) => ({
117147
attachments: many(attachments),
118148
module: one(modules, {
@@ -121,16 +151,6 @@ export const segmentsRelations = relations(segments, ({ one, many }) => ({
121151
}),
122152
}));
123153

124-
export const attachments = tableCreator("attachment", {
125-
id: serial("id").primaryKey(),
126-
segmentId: serial("segmentId")
127-
.notNull()
128-
.references(() => segments.id, { onDelete: "cascade" }),
129-
fileName: text("fileName").notNull(),
130-
fileKey: text("fileKey").notNull(),
131-
createdAt: timestamp("created_at").notNull().defaultNow(),
132-
});
133-
134154
export const attachmentsRelations = relations(attachments, ({ one }) => ({
135155
segment: one(segments, {
136156
fields: [attachments.segmentId],
@@ -149,3 +169,5 @@ export type Progress = typeof progress.$inferSelect;
149169
export type ProgressCreate = typeof progress.$inferInsert;
150170
export type Module = typeof modules.$inferSelect;
151171
export type ModuleCreate = typeof modules.$inferInsert;
172+
export type Testimonial = typeof testimonials.$inferSelect;
173+
export type TestimonialCreate = typeof testimonials.$inferInsert;

app/routeTree.gen.ts

+26
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { Route as SuccessImport } from './routes/success'
2020
import { Route as PurchaseImport } from './routes/purchase'
2121
import { Route as PrivacyPolicyImport } from './routes/privacy-policy'
2222
import { Route as LoginImport } from './routes/login'
23+
import { Route as CreateTestimonialImport } from './routes/create-testimonial'
2324
import { Route as CancelImport } from './routes/cancel'
2425
import { Route as AboutImport } from './routes/about'
2526
import { Route as IndexImport } from './routes/index'
@@ -80,6 +81,12 @@ const LoginRoute = LoginImport.update({
8081
getParentRoute: () => rootRoute,
8182
} as any)
8283

84+
const CreateTestimonialRoute = CreateTestimonialImport.update({
85+
id: '/create-testimonial',
86+
path: '/create-testimonial',
87+
getParentRoute: () => rootRoute,
88+
} as any)
89+
8390
const CancelRoute = CancelImport.update({
8491
id: '/cancel',
8592
path: '/cancel',
@@ -176,6 +183,13 @@ declare module '@tanstack/react-router' {
176183
preLoaderRoute: typeof CancelImport
177184
parentRoute: typeof rootRoute
178185
}
186+
'/create-testimonial': {
187+
id: '/create-testimonial'
188+
path: '/create-testimonial'
189+
fullPath: '/create-testimonial'
190+
preLoaderRoute: typeof CreateTestimonialImport
191+
parentRoute: typeof rootRoute
192+
}
179193
'/login': {
180194
id: '/login'
181195
path: '/login'
@@ -323,6 +337,7 @@ export interface FileRoutesByFullPath {
323337
'/': typeof IndexRoute
324338
'/about': typeof AboutRoute
325339
'/cancel': typeof CancelRoute
340+
'/create-testimonial': typeof CreateTestimonialRoute
326341
'/login': typeof LoginRoute
327342
'/privacy-policy': typeof PrivacyPolicyRoute
328343
'/purchase': typeof PurchaseRoute
@@ -344,6 +359,7 @@ export interface FileRoutesByTo {
344359
'/': typeof IndexRoute
345360
'/about': typeof AboutRoute
346361
'/cancel': typeof CancelRoute
362+
'/create-testimonial': typeof CreateTestimonialRoute
347363
'/login': typeof LoginRoute
348364
'/privacy-policy': typeof PrivacyPolicyRoute
349365
'/purchase': typeof PurchaseRoute
@@ -365,6 +381,7 @@ export interface FileRoutesById {
365381
'/': typeof IndexRoute
366382
'/about': typeof AboutRoute
367383
'/cancel': typeof CancelRoute
384+
'/create-testimonial': typeof CreateTestimonialRoute
368385
'/login': typeof LoginRoute
369386
'/privacy-policy': typeof PrivacyPolicyRoute
370387
'/purchase': typeof PurchaseRoute
@@ -389,6 +406,7 @@ export interface FileRouteTypes {
389406
| '/'
390407
| '/about'
391408
| '/cancel'
409+
| '/create-testimonial'
392410
| '/login'
393411
| '/privacy-policy'
394412
| '/purchase'
@@ -409,6 +427,7 @@ export interface FileRouteTypes {
409427
| '/'
410428
| '/about'
411429
| '/cancel'
430+
| '/create-testimonial'
412431
| '/login'
413432
| '/privacy-policy'
414433
| '/purchase'
@@ -428,6 +447,7 @@ export interface FileRouteTypes {
428447
| '/'
429448
| '/about'
430449
| '/cancel'
450+
| '/create-testimonial'
431451
| '/login'
432452
| '/privacy-policy'
433453
| '/purchase'
@@ -451,6 +471,7 @@ export interface RootRouteChildren {
451471
IndexRoute: typeof IndexRoute
452472
AboutRoute: typeof AboutRoute
453473
CancelRoute: typeof CancelRoute
474+
CreateTestimonialRoute: typeof CreateTestimonialRoute
454475
LoginRoute: typeof LoginRoute
455476
PrivacyPolicyRoute: typeof PrivacyPolicyRoute
456477
PurchaseRoute: typeof PurchaseRoute
@@ -470,6 +491,7 @@ const rootRouteChildren: RootRouteChildren = {
470491
IndexRoute: IndexRoute,
471492
AboutRoute: AboutRoute,
472493
CancelRoute: CancelRoute,
494+
CreateTestimonialRoute: CreateTestimonialRoute,
473495
LoginRoute: LoginRoute,
474496
PrivacyPolicyRoute: PrivacyPolicyRoute,
475497
PurchaseRoute: PurchaseRoute,
@@ -498,6 +520,7 @@ export const routeTree = rootRoute
498520
"/",
499521
"/about",
500522
"/cancel",
523+
"/create-testimonial",
501524
"/login",
502525
"/privacy-policy",
503526
"/purchase",
@@ -522,6 +545,9 @@ export const routeTree = rootRoute
522545
"/cancel": {
523546
"filePath": "cancel.tsx"
524547
},
548+
"/create-testimonial": {
549+
"filePath": "create-testimonial.tsx"
550+
},
525551
"/login": {
526552
"filePath": "login.tsx"
527553
},

0 commit comments

Comments
 (0)