Skip to content
This repository was archived by the owner on May 20, 2025. It is now read-only.

Commit 4383c22

Browse files
committed
link schema and formid
1 parent c0ba2ac commit 4383c22

File tree

2 files changed

+86
-28
lines changed

2 files changed

+86
-28
lines changed

docs/guides/nodejs/survey-application.mdx

Lines changed: 85 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,26 @@ Create a file at `form/schema.ts`:
6363
```ts title:src/forms/form/schema.ts
6464
import { z } from 'zod'
6565

66-
export const SubmissionSchema = z.object({
66+
export const feedbackSchema = z.object({
6767
name: z.string(),
6868
rating: z.number().min(1).max(5),
6969
feedback: z.string().optional(),
7070
})
7171

72-
export type Submission = z.infer<typeof SubmissionSchema>
72+
export const rsvpSchema = z.object({
73+
name: z.string(),
74+
attending: z.boolean(),
75+
guests: z.number().int().min(0),
76+
})
77+
78+
export const formSchemas: Record<string, z.ZodObject<any>> = {
79+
feedback: feedbackSchema,
80+
rsvp: rsvpSchema,
81+
}
7382
```
7483

75-
This schema ensures that any incoming submission contains a valid name, a 1–5 rating, and optional feedback.
84+
Feedback Schema: Validates that submissions include a name (string), a rating (number between 1 and 5), and optional feedback (string).
85+
RSVP Schema: Validates that submissions include a name (string), an attending status (boolean), and the number of guests (non-negative integer).
7686

7787
## Step 1: Define Resources
7888

@@ -94,18 +104,28 @@ Create an API route that validates and stores form submissions, then triggers fu
94104
```ts title:services/forms.ts
95105
import { api } from '@nitric/sdk'
96106
import { submissions, submitted } from '../resources/resources'
97-
import { SubmissionSchema } from '../form/schema'
107+
import { formSchemas } from '../form/schema'
98108

99109
const formApi = api('forms')
100110

101111
formApi.post('/forms/:formId', async (ctx) => {
102112
const formId = ctx.req.params.formId
103-
const parsed = SubmissionSchema.safeParse(ctx.req.json())
113+
const schema = formSchemas[formId]
114+
115+
if (!schema) {
116+
ctx.res.status = 400
117+
ctx.res.json({ msg: `Unknown formId: ${formId}` })
118+
return
119+
}
120+
121+
const parsed = schema.safeParse(ctx.req.json())
122+
104123
if (!parsed.success) {
105124
ctx.res.status = 400
106125
ctx.res.json({ msg: 'Invalid submission', errors: parsed.error.format() })
107126
return
108127
}
128+
109129
const data = parsed.data
110130
const id = `${formId}-${Date.now()}`
111131

@@ -125,7 +145,7 @@ import { receipts, submissions, output } from '../resources/resources'
125145
import { buildReceipt } from '../form/receipt'
126146

127147
receipts.subscribe(async (ctx) => {
128-
const { id } = ctx.req.json()
148+
const { id, formId } = ctx.req.json()
129149
const submission = await submissions.get(id)
130150

131151
if (!submission) {
@@ -134,7 +154,7 @@ receipts.subscribe(async (ctx) => {
134154
}
135155

136156
// Build the PDF buffer from the submission data
137-
const buffer = await buildReceipt(submission)
157+
const buffer = await buildReceipt(submission, formId)
138158

139159
// Store the PDF file in the bucket
140160
const file = output.file(`${id}.pdf`)
@@ -148,45 +168,66 @@ receipts.subscribe(async (ctx) => {
148168

149169
```ts title:form/receipt.ts
150170
import PDFDocument from 'pdfkit'
151-
import { Submission } from './schema'
171+
import { feedbackSchema, rsvpSchema } from './schema'
172+
import { z } from 'zod'
173+
174+
type FeedbackSubmission = z.infer<typeof feedbackSchema>
175+
type RsvpSubmission = z.infer<typeof rsvpSchema>
152176

153-
export const buildReceipt = async (data: Submission) => {
177+
export const buildReceipt = async (
178+
data: any,
179+
formId: string,
180+
): Promise<Buffer> => {
154181
const receipt = new PDFDocument({ bufferPages: true })
155182

156183
const doneWriting = new Promise<Buffer>((resolve) => {
157184
const buffers: Uint8Array[] = []
158185

159-
// Collect PDF output in memory as chunks
160186
receipt.on('data', buffers.push.bind(buffers))
161187
receipt.on('end', () => {
162188
const pdfData = Buffer.concat(buffers)
163189
resolve(pdfData)
164190
})
165191

166-
const { name, rating, feedback } = data
167-
168-
// Write header
169192
receipt.font('Times-Roman').fontSize(20).text('Survey - Receipt', 100, 100)
170-
171-
// Write section title
172193
receipt
173194
.font('Times-Roman')
174195
.fontSize(16)
175-
.text('Primary Applicant Details', 100, 150)
196+
.text('Submission Details', 100, 150)
176197

177-
// Write submission details
178-
receipt
179-
.font('Times-Roman')
180-
.fontSize(12)
181-
.text(
182-
`Name: ${name}
198+
if (formId === 'feedback') {
199+
const { name, rating, feedback } = data as FeedbackSubmission
200+
201+
receipt
202+
.font('Times-Roman')
203+
.fontSize(12)
204+
.text(
205+
`Name: ${name}
183206
Rating: ${rating}
184207
Feedback: ${feedback || 'N/A'}`,
185-
100,
186-
175,
187-
)
208+
100,
209+
175,
210+
)
211+
} else if (formId === 'rsvp') {
212+
const { name, attending, guests } = data as RsvpSubmission
213+
214+
receipt
215+
.font('Times-Roman')
216+
.fontSize(12)
217+
.text(
218+
`Name: ${name}
219+
Attending: ${attending ? 'Yes' : 'No'}
220+
Guests: ${guests}`,
221+
100,
222+
175,
223+
)
224+
} else {
225+
receipt
226+
.font('Times-Roman')
227+
.fontSize(12)
228+
.text('Unknown form type. No details available.', 100, 175)
229+
}
188230

189-
// Finalize the PDF
190231
receipt.end()
191232
})
192233

@@ -206,7 +247,7 @@ import { receipts } from '../resources/resources'
206247
receipts.subscribe(async (ctx) => {
207248
const { id } = ctx.req.json()
208249

209-
// Handle delivery or hook into a real email/SaaS integration
250+
// Simulate delivery or hook into a real email/SaaS integration
210251
console.log(`Delivering receipt for submission: ${id}`)
211252
})
212253
```
@@ -239,6 +280,8 @@ nitric start
239280

240281
Use the dashboard to submit your survey data -
241282

283+
Form ID: feedback
284+
242285
```json
243286
{
244287
"name": "Jane",
@@ -247,10 +290,25 @@ Use the dashboard to submit your survey data -
247290
}
248291
```
249292

293+
Form ID: rsvp
294+
295+
```json
296+
{
297+
"name": "Jane",
298+
"attending": true,
299+
"guests": 5
300+
}
301+
```
302+
250303
![Submit Form](/docs/images/guides/survey-application/submit.png)
251304

252305
You should see messages in your console for PDF generation and delivery.
253306

307+
```bash
308+
Delivering receipt for submission: rsvp-1744131025791
309+
Receipt stored for rsvp-1744131025791
310+
```
311+
254312
### Get a Receipt
255313

256314
Replace `<timestamp>` with the value returned from the submission.

docs/guides/nodejs/survey-website.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ const SurveyForm = () => {
110110
const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
111111
e.preventDefault()
112112
try {
113-
const response = await fetch('/api/forms/forms/test-survey', {
113+
const response = await fetch('/api/forms/forms/feedback', {
114114
method: 'POST',
115115
headers: {
116116
'Content-Type': 'application/json',

0 commit comments

Comments
 (0)