271 lines
12 KiB
JavaScript
271 lines
12 KiB
JavaScript
/**
|
|
* Seed script for MOPC Onboarding Form (ESM version for production)
|
|
* Run with: node prisma/seed-mopc-onboarding.mjs
|
|
*/
|
|
|
|
import { PrismaClient } from '@prisma/client'
|
|
|
|
const prisma = new PrismaClient()
|
|
|
|
const MOPC_FORM_CONFIG = {
|
|
name: 'MOPC Application 2026',
|
|
description: 'Monaco Ocean Protection Challenge application form',
|
|
publicSlug: 'mopc-2026',
|
|
status: 'PUBLISHED',
|
|
isPublic: true,
|
|
sendConfirmationEmail: true,
|
|
sendTeamInviteEmails: true,
|
|
confirmationEmailSubject: 'Application Received - Monaco Ocean Protection Challenge',
|
|
confirmationEmailBody: `Thank you for applying to the Monaco Ocean Protection Challenge 2026!
|
|
|
|
We have received your application and our team will review it carefully.
|
|
|
|
If you have any questions, please don't hesitate to reach out.
|
|
|
|
Good luck!
|
|
The MOPC Team`,
|
|
confirmationMessage: 'Thank you for your application! We have sent a confirmation email to the address you provided. Our team will review your submission and get back to you soon.',
|
|
}
|
|
|
|
const STEPS = [
|
|
{
|
|
name: 'category',
|
|
title: 'Competition Category',
|
|
description: 'Select your competition track',
|
|
sortOrder: 0,
|
|
isOptional: false,
|
|
fields: [
|
|
{
|
|
name: 'competitionCategory',
|
|
label: 'Which category best describes your project?',
|
|
fieldType: 'RADIO',
|
|
specialType: 'COMPETITION_CATEGORY',
|
|
required: true,
|
|
sortOrder: 0,
|
|
width: 'full',
|
|
projectMapping: 'competitionCategory',
|
|
description: 'Choose the category that best fits your stage of development',
|
|
optionsJson: [
|
|
{ value: 'STARTUP', label: 'Startup', description: 'You have an existing company or registered business entity' },
|
|
{ value: 'BUSINESS_CONCEPT', label: 'Business Concept', description: 'You are a student, graduate, or have an idea not yet incorporated' },
|
|
],
|
|
},
|
|
],
|
|
},
|
|
{
|
|
name: 'contact',
|
|
title: 'Contact Information',
|
|
description: 'Tell us how to reach you',
|
|
sortOrder: 1,
|
|
isOptional: false,
|
|
fields: [
|
|
{ name: 'contactName', label: 'Full Name', fieldType: 'TEXT', required: true, sortOrder: 0, width: 'half', placeholder: 'Enter your full name' },
|
|
{ name: 'contactEmail', label: 'Email Address', fieldType: 'EMAIL', required: true, sortOrder: 1, width: 'half', placeholder: 'your.email@example.com', description: 'We will use this email for all communications' },
|
|
{ name: 'contactPhone', label: 'Phone Number', fieldType: 'PHONE', required: true, sortOrder: 2, width: 'half', placeholder: '+1 (555) 123-4567' },
|
|
{ name: 'country', label: 'Country', fieldType: 'SELECT', specialType: 'COUNTRY_SELECT', required: true, sortOrder: 3, width: 'half', projectMapping: 'country' },
|
|
{ name: 'city', label: 'City', fieldType: 'TEXT', required: false, sortOrder: 4, width: 'half', placeholder: 'City name' },
|
|
],
|
|
},
|
|
{
|
|
name: 'project',
|
|
title: 'Project Details',
|
|
description: 'Tell us about your ocean protection project',
|
|
sortOrder: 2,
|
|
isOptional: false,
|
|
fields: [
|
|
{ name: 'projectName', label: 'Project Name', fieldType: 'TEXT', required: true, sortOrder: 0, width: 'full', projectMapping: 'title', maxLength: 200, placeholder: 'Give your project a memorable name' },
|
|
{ name: 'teamName', label: 'Team / Company Name', fieldType: 'TEXT', required: false, sortOrder: 1, width: 'half', projectMapping: 'teamName', placeholder: 'Your team or company name' },
|
|
{ name: 'oceanIssue', label: 'Primary Ocean Issue', fieldType: 'SELECT', specialType: 'OCEAN_ISSUE', required: true, sortOrder: 2, width: 'half', projectMapping: 'oceanIssue', description: 'Select the primary ocean issue your project addresses' },
|
|
{ name: 'description', label: 'Project Description', fieldType: 'TEXTAREA', required: true, sortOrder: 3, width: 'full', projectMapping: 'description', minLength: 50, maxLength: 2000, placeholder: 'Describe your project, its goals, and how it will help protect the ocean...', description: 'Provide a clear description of your project (50-2000 characters)' },
|
|
{ name: 'websiteUrl', label: 'Website URL', fieldType: 'URL', required: false, sortOrder: 4, width: 'half', projectMapping: 'websiteUrl', placeholder: 'https://yourproject.com' },
|
|
],
|
|
},
|
|
{
|
|
name: 'team',
|
|
title: 'Team Members',
|
|
description: 'Add your team members (they will receive email invitations)',
|
|
sortOrder: 3,
|
|
isOptional: true,
|
|
fields: [
|
|
{ name: 'teamMembers', label: 'Team Members', fieldType: 'TEXT', specialType: 'TEAM_MEMBERS', required: false, sortOrder: 0, width: 'full', description: 'Add up to 5 team members. They will receive an invitation email to join your application.' },
|
|
],
|
|
},
|
|
{
|
|
name: 'additional',
|
|
title: 'Additional Details',
|
|
description: 'A few more questions about your project',
|
|
sortOrder: 4,
|
|
isOptional: false,
|
|
fields: [
|
|
{ name: 'institution', label: 'University / School', fieldType: 'TEXT', required: false, sortOrder: 0, width: 'half', projectMapping: 'institution', placeholder: 'Name of your institution', conditionJson: { field: 'competitionCategory', operator: 'equals', value: 'BUSINESS_CONCEPT' } },
|
|
{ name: 'startupCreatedDate', label: 'Startup Founded Date', fieldType: 'DATE', required: false, sortOrder: 1, width: 'half', description: 'When was your company founded?', conditionJson: { field: 'competitionCategory', operator: 'equals', value: 'STARTUP' } },
|
|
{ name: 'wantsMentorship', label: 'I am interested in receiving mentorship', fieldType: 'CHECKBOX', required: false, sortOrder: 2, width: 'full', projectMapping: 'wantsMentorship', description: 'Check this box if you would like to be paired with an expert mentor' },
|
|
{ name: 'referralSource', label: 'How did you hear about MOPC?', fieldType: 'SELECT', required: false, sortOrder: 3, width: 'half', optionsJson: [
|
|
{ value: 'social_media', label: 'Social Media' },
|
|
{ value: 'search_engine', label: 'Search Engine' },
|
|
{ value: 'word_of_mouth', label: 'Word of Mouth' },
|
|
{ value: 'university', label: 'University / School' },
|
|
{ value: 'partner', label: 'Partner Organization' },
|
|
{ value: 'media', label: 'News / Media' },
|
|
{ value: 'event', label: 'Event / Conference' },
|
|
{ value: 'other', label: 'Other' },
|
|
]},
|
|
],
|
|
},
|
|
{
|
|
name: 'review',
|
|
title: 'Review & Submit',
|
|
description: 'Review your application and accept the terms',
|
|
sortOrder: 5,
|
|
isOptional: false,
|
|
fields: [
|
|
{ name: 'instructions', label: 'Review Instructions', fieldType: 'INSTRUCTIONS', required: false, sortOrder: 0, width: 'full', description: 'Please review all the information you have provided. Once submitted, you will not be able to make changes.' },
|
|
{ name: 'gdprConsent', label: 'I consent to the processing of my personal data in accordance with the GDPR and the MOPC Privacy Policy', fieldType: 'CHECKBOX', specialType: 'GDPR_CONSENT', required: true, sortOrder: 1, width: 'full' },
|
|
{ name: 'termsAccepted', label: 'I have read and accept the Terms and Conditions of the Monaco Ocean Protection Challenge', fieldType: 'CHECKBOX', required: true, sortOrder: 2, width: 'full' },
|
|
],
|
|
},
|
|
]
|
|
|
|
async function main() {
|
|
console.log('Seeding MOPC onboarding form...')
|
|
|
|
// Check if form already exists
|
|
const existingForm = await prisma.applicationForm.findUnique({
|
|
where: { publicSlug: MOPC_FORM_CONFIG.publicSlug },
|
|
})
|
|
|
|
if (existingForm) {
|
|
console.log('Form with slug "mopc-2026" already exists. Updating...')
|
|
|
|
// Delete existing steps and fields to recreate them
|
|
await prisma.applicationFormField.deleteMany({ where: { formId: existingForm.id } })
|
|
await prisma.onboardingStep.deleteMany({ where: { formId: existingForm.id } })
|
|
|
|
// Update the form
|
|
await prisma.applicationForm.update({
|
|
where: { id: existingForm.id },
|
|
data: {
|
|
name: MOPC_FORM_CONFIG.name,
|
|
description: MOPC_FORM_CONFIG.description,
|
|
status: MOPC_FORM_CONFIG.status,
|
|
isPublic: MOPC_FORM_CONFIG.isPublic,
|
|
sendConfirmationEmail: MOPC_FORM_CONFIG.sendConfirmationEmail,
|
|
sendTeamInviteEmails: MOPC_FORM_CONFIG.sendTeamInviteEmails,
|
|
confirmationEmailSubject: MOPC_FORM_CONFIG.confirmationEmailSubject,
|
|
confirmationEmailBody: MOPC_FORM_CONFIG.confirmationEmailBody,
|
|
confirmationMessage: MOPC_FORM_CONFIG.confirmationMessage,
|
|
},
|
|
})
|
|
|
|
// Create steps and fields
|
|
for (const stepData of STEPS) {
|
|
const step = await prisma.onboardingStep.create({
|
|
data: {
|
|
formId: existingForm.id,
|
|
name: stepData.name,
|
|
title: stepData.title,
|
|
description: stepData.description,
|
|
sortOrder: stepData.sortOrder,
|
|
isOptional: stepData.isOptional,
|
|
},
|
|
})
|
|
|
|
for (const field of stepData.fields) {
|
|
await prisma.applicationFormField.create({
|
|
data: {
|
|
formId: existingForm.id,
|
|
stepId: step.id,
|
|
name: field.name,
|
|
label: field.label,
|
|
fieldType: field.fieldType,
|
|
specialType: field.specialType || null,
|
|
required: field.required,
|
|
sortOrder: field.sortOrder,
|
|
width: field.width,
|
|
description: field.description || null,
|
|
placeholder: field.placeholder || null,
|
|
projectMapping: field.projectMapping || null,
|
|
minLength: field.minLength || null,
|
|
maxLength: field.maxLength || null,
|
|
optionsJson: field.optionsJson || undefined,
|
|
conditionJson: field.conditionJson || undefined,
|
|
},
|
|
})
|
|
}
|
|
console.log(` - Created step: ${stepData.title} (${stepData.fields.length} fields)`)
|
|
}
|
|
|
|
console.log(`\nForm updated: ${existingForm.id}`)
|
|
return
|
|
}
|
|
|
|
// Create new form
|
|
const form = await prisma.applicationForm.create({
|
|
data: {
|
|
name: MOPC_FORM_CONFIG.name,
|
|
description: MOPC_FORM_CONFIG.description,
|
|
publicSlug: MOPC_FORM_CONFIG.publicSlug,
|
|
status: MOPC_FORM_CONFIG.status,
|
|
isPublic: MOPC_FORM_CONFIG.isPublic,
|
|
sendConfirmationEmail: MOPC_FORM_CONFIG.sendConfirmationEmail,
|
|
sendTeamInviteEmails: MOPC_FORM_CONFIG.sendTeamInviteEmails,
|
|
confirmationEmailSubject: MOPC_FORM_CONFIG.confirmationEmailSubject,
|
|
confirmationEmailBody: MOPC_FORM_CONFIG.confirmationEmailBody,
|
|
confirmationMessage: MOPC_FORM_CONFIG.confirmationMessage,
|
|
},
|
|
})
|
|
|
|
console.log(`Created form: ${form.id}`)
|
|
|
|
// Create steps and fields
|
|
for (const stepData of STEPS) {
|
|
const step = await prisma.onboardingStep.create({
|
|
data: {
|
|
formId: form.id,
|
|
name: stepData.name,
|
|
title: stepData.title,
|
|
description: stepData.description,
|
|
sortOrder: stepData.sortOrder,
|
|
isOptional: stepData.isOptional,
|
|
},
|
|
})
|
|
|
|
for (const field of stepData.fields) {
|
|
await prisma.applicationFormField.create({
|
|
data: {
|
|
formId: form.id,
|
|
stepId: step.id,
|
|
name: field.name,
|
|
label: field.label,
|
|
fieldType: field.fieldType,
|
|
specialType: field.specialType || null,
|
|
required: field.required,
|
|
sortOrder: field.sortOrder,
|
|
width: field.width,
|
|
description: field.description || null,
|
|
placeholder: field.placeholder || null,
|
|
projectMapping: field.projectMapping || null,
|
|
minLength: field.minLength || null,
|
|
maxLength: field.maxLength || null,
|
|
optionsJson: field.optionsJson || undefined,
|
|
conditionJson: field.conditionJson || undefined,
|
|
},
|
|
})
|
|
}
|
|
console.log(` - Created step: ${stepData.title} (${stepData.fields.length} fields)`)
|
|
}
|
|
|
|
console.log(`\nMOPC form seeded successfully!`)
|
|
console.log(`Form ID: ${form.id}`)
|
|
console.log(`Public URL: /apply/${form.publicSlug}`)
|
|
}
|
|
|
|
main()
|
|
.catch((e) => {
|
|
console.error(e)
|
|
process.exit(1)
|
|
})
|
|
.finally(async () => {
|
|
await prisma.$disconnect()
|
|
})
|