mirror of
https://github.com/soconnor0919/hristudio.git
synced 2026-05-08 13:58:55 -04:00
feat: complete forms system overhaul
- Add new forms table with type (consent/survey/questionnaire) - Add formResponses table for submissions - Add forms API router with full CRUD: - list, get, create, update, delete - setActive, createVersion - getResponses, submitResponse - Add forms list page with card-based UI - Add form builder with field types (text, textarea, multiple_choice, checkbox, rating, yes_no, date, signature) - Add form viewer with edit mode and preview - Add responses viewing with participant info
This commit is contained in:
@@ -68,6 +68,29 @@ export const stepTypeEnum = pgEnum("step_type", [
|
||||
"conditional",
|
||||
]);
|
||||
|
||||
export const formTypeEnum = pgEnum("form_type", [
|
||||
"consent",
|
||||
"survey",
|
||||
"questionnaire",
|
||||
]);
|
||||
|
||||
export const formFieldTypeEnum = pgEnum("form_field_type", [
|
||||
"text",
|
||||
"textarea",
|
||||
"multiple_choice",
|
||||
"checkbox",
|
||||
"rating",
|
||||
"yes_no",
|
||||
"date",
|
||||
"signature",
|
||||
]);
|
||||
|
||||
export const formResponseStatusEnum = pgEnum("form_response_status", [
|
||||
"pending",
|
||||
"completed",
|
||||
"rejected",
|
||||
]);
|
||||
|
||||
export const communicationProtocolEnum = pgEnum("communication_protocol", [
|
||||
"rest",
|
||||
"ros2",
|
||||
@@ -594,6 +617,64 @@ export const consentForms = createTable(
|
||||
}),
|
||||
);
|
||||
|
||||
// New unified forms table
|
||||
export const forms = createTable(
|
||||
"form",
|
||||
{
|
||||
id: uuid("id").notNull().primaryKey().defaultRandom(),
|
||||
studyId: uuid("study_id")
|
||||
.notNull()
|
||||
.references(() => studies.id, { onDelete: "cascade" }),
|
||||
type: formTypeEnum("type").notNull(),
|
||||
title: varchar("title", { length: 255 }).notNull(),
|
||||
description: text("description"),
|
||||
version: integer("version").default(1).notNull(),
|
||||
active: boolean("active").default(true).notNull(),
|
||||
fields: jsonb("fields").notNull().default([]),
|
||||
settings: jsonb("settings").default({}),
|
||||
createdBy: text("created_by")
|
||||
.notNull()
|
||||
.references(() => users.id),
|
||||
createdAt: timestamp("created_at", { withTimezone: true })
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull(),
|
||||
updatedAt: timestamp("updated_at", { withTimezone: true })
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull(),
|
||||
},
|
||||
(table) => ({
|
||||
studyVersionUnique: unique().on(table.studyId, table.version),
|
||||
}),
|
||||
);
|
||||
|
||||
// Form responses/submissions
|
||||
export const formResponses = createTable(
|
||||
"form_response",
|
||||
{
|
||||
id: uuid("id").notNull().primaryKey().defaultRandom(),
|
||||
formId: uuid("form_id")
|
||||
.notNull()
|
||||
.references(() => forms.id, { onDelete: "cascade" }),
|
||||
participantId: uuid("participant_id")
|
||||
.notNull()
|
||||
.references(() => participants.id, { onDelete: "cascade" }),
|
||||
responses: jsonb("responses").notNull().default({}),
|
||||
status: formResponseStatusEnum("status").default("pending"),
|
||||
signatureData: text("signature_data"),
|
||||
signedAt: timestamp("signed_at", { withTimezone: true }),
|
||||
ipAddress: inet("ip_address"),
|
||||
submittedAt: timestamp("submitted_at", { withTimezone: true })
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull(),
|
||||
createdAt: timestamp("created_at", { withTimezone: true })
|
||||
.default(sql`CURRENT_TIMESTAMP`)
|
||||
.notNull(),
|
||||
},
|
||||
(table) => ({
|
||||
formParticipantUnique: unique().on(table.formId, table.participantId),
|
||||
}),
|
||||
);
|
||||
|
||||
export const participantConsents = createTable(
|
||||
"participant_consent",
|
||||
{
|
||||
@@ -1118,6 +1199,29 @@ export const participantConsentsRelations = relations(
|
||||
}),
|
||||
);
|
||||
|
||||
export const formsRelations = relations(forms, ({ one, many }) => ({
|
||||
study: one(studies, {
|
||||
fields: [forms.studyId],
|
||||
references: [studies.id],
|
||||
}),
|
||||
createdBy: one(users, {
|
||||
fields: [forms.createdBy],
|
||||
references: [users.id],
|
||||
}),
|
||||
responses: many(formResponses),
|
||||
}));
|
||||
|
||||
export const formResponsesRelations = relations(formResponses, ({ one }) => ({
|
||||
form: one(forms, {
|
||||
fields: [formResponses.formId],
|
||||
references: [forms.id],
|
||||
}),
|
||||
participant: one(participants, {
|
||||
fields: [formResponses.participantId],
|
||||
references: [participants.id],
|
||||
}),
|
||||
}));
|
||||
|
||||
export const robotsRelations = relations(robots, ({ many }) => ({
|
||||
experiments: many(experiments),
|
||||
plugins: many(plugins),
|
||||
|
||||
Reference in New Issue
Block a user