diff --git a/admin.html b/admin.html index c39ea63..ba0f71c 100644 --- a/admin.html +++ b/admin.html @@ -791,6 +791,52 @@ +
${app.food_preference || '-'}
+${app.volunteer_interest ? '✓ Yes' : 'No'}
+${app.coupon_code}
+Dear ${application.first_name},
- -We've received your application to join Valley of the Commons (August 24 - September 20, 2026).
+Your application to Valley of the Commons (August 24 – September 20, 2026) has been received. We're excited to read about what you'll bring to the village.
If you have any questions, reply to this email and we'll get back to you.
+If you have any questions, just reply to this email — we'd love to hear from you.
With warmth,
@@ -212,7 +209,7 @@ module.exports = async function handler(req, res) {
const data = req.body;
// Validate required fields
- const required = ['first_name', 'last_name', 'email', 'motivation', 'code_of_conduct_accepted', 'privacy_policy_accepted'];
+ const required = ['first_name', 'last_name', 'email', 'motivation', 'belief_update', 'privacy_policy_accepted'];
for (const field of required) {
if (!data[field]) {
return res.status(400).json({ error: `Missing required field: ${field}` });
@@ -244,6 +241,10 @@ module.exports = async function handler(req, res) {
const governance = Array.isArray(data.governance_interest) ? data.governance_interest : (data.governance_interest ? [data.governance_interest] : null);
const previousEvents = Array.isArray(data.previous_events) ? data.previous_events : (data.previous_events ? [data.previous_events] : null);
+ // Prepare new array fields
+ const selectedWeeks = Array.isArray(data.weeks) ? data.weeks : (data.weeks ? [data.weeks] : []);
+ const topThemes = Array.isArray(data.top_themes) ? data.top_themes : (data.top_themes ? [data.top_themes] : null);
+
// Insert application
const result = await pool.query(
`INSERT INTO applications (
@@ -255,11 +256,14 @@ module.exports = async function handler(req, res) {
how_heard, referral_name, previous_events, emergency_name, emergency_phone,
emergency_relationship, code_of_conduct_accepted, privacy_policy_accepted,
photo_consent, scholarship_needed, scholarship_reason, contribution_amount,
- ip_address, user_agent, need_accommodation, want_food, accommodation_type
+ ip_address, user_agent, need_accommodation, want_food, accommodation_type,
+ selected_weeks, top_themes, belief_update, volunteer_interest, coupon_code,
+ food_preference, accessibility_needs
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17,
$18, $19, $20, $21, $22, $23, $24, $25, $26, $27, $28, $29, $30, $31, $32,
- $33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43, $44
+ $33, $34, $35, $36, $37, $38, $39, $40, $41, $42, $43, $44,
+ $45, $46, $47, $48, $49, $50, $51
) RETURNING id, submitted_at`,
[
data.first_name?.trim(),
@@ -305,11 +309,17 @@ module.exports = async function handler(req, res) {
req.headers['user-agent'] || null,
data.need_accommodation || false,
data.want_food || false,
- data.accommodation_type || null
+ data.accommodation_type || null,
+ selectedWeeks.length > 0 ? selectedWeeks : null,
+ topThemes,
+ data.belief_update?.trim() || null,
+ data.volunteer_interest || false,
+ data.coupon_code?.trim() || null,
+ data.food_preference?.trim() || null,
+ data.accessibility_needs?.trim() || null
]
);
- const weeksSelected = Array.isArray(data.weeks) ? data.weeks : [];
const application = {
id: result.rows[0].id,
submitted_at: result.rows[0].submitted_at,
@@ -328,7 +338,7 @@ module.exports = async function handler(req, res) {
referral_name: data.referral_name,
arrival_date: data.arrival_date,
departure_date: data.departure_date,
- weeks: weeksSelected,
+ weeks: selectedWeeks,
need_accommodation: data.need_accommodation || false,
accommodation_preference: data.accommodation_preference || null,
accommodation_type: data.accommodation_type || null,
@@ -342,7 +352,7 @@ module.exports = async function handler(req, res) {
// Add to Listmonk newsletter
addToListmonk(application.email, `${application.first_name} ${application.last_name}`, {
source: 'application',
- weeks: weeksSelected,
+ weeks: selectedWeeks,
contributionAmount: data.contribution_amount,
}).catch(err => console.error('[Listmonk] Application sync failed:', err.message));
@@ -382,17 +392,17 @@ module.exports = async function handler(req, res) {
// Create Mollie payment for registration + accommodation fee
let checkoutUrl = null;
- if (weeksSelected.length > 0 && process.env.MOLLIE_API_KEY) {
+ if (selectedWeeks.length > 0 && process.env.MOLLIE_API_KEY) {
try {
const paymentResult = await createPayment(
application.id,
'registration',
- weeksSelected.length,
+ selectedWeeks.length,
application.email,
application.first_name,
application.last_name,
application.accommodation_type,
- weeksSelected
+ selectedWeeks
);
checkoutUrl = paymentResult.checkoutUrl;
console.log(`Mollie payment created: ${paymentResult.paymentId} (€${paymentResult.amount})`);
diff --git a/api/mollie.js b/api/mollie.js
index 466b302..c1255d9 100644
--- a/api/mollie.js
+++ b/api/mollie.js
@@ -226,7 +226,7 @@ const paymentConfirmationEmail = (application, bookingResult) => {
${bookingHtml}
-
Your application is now complete. Our team will review it and get back to you within 2-3 weeks.
+Your application is now complete. Our team will review it and get back to you within 1 week.
If you have any questions, reply to this email and we'll get back to you.
diff --git a/apply.html b/apply.html index 26febdc..4769529 100644 --- a/apply.html +++ b/apply.html @@ -58,36 +58,10 @@ padding: 2rem; } - .intro { - text-align: center; - margin-bottom: 2rem; - padding: 2rem; - background: white; - border-radius: 12px; - } - - .intro h1 { - font-family: 'Cormorant Garamond', serif; - font-size: 2.25rem; - color: var(--forest); - margin-bottom: 1rem; - } - - .intro p { color: #666; font-size: 0.95rem; } - - .event-badge { - display: inline-block; - background: var(--forest); - color: white; - padding: 0.5rem 1rem; - border-radius: 20px; - font-size: 0.875rem; - margin-bottom: 1rem; - } - /* Progress */ .progress-container { margin-bottom: 2rem; + display: none; } .progress-bar { @@ -196,7 +170,8 @@ .week-card:hover { border-color: var(--forest-light); } .week-card.selected { border-color: var(--forest); background: rgba(45, 80, 22, 0.05); } - .week-card input { display: none; } + .week-card input[type="checkbox"], + .week-card input[type="radio"] { display: none; } .week-card h4 { font-size: 0.95rem; color: var(--forest); margin-bottom: 0.25rem; } .week-card .dates { font-size: 0.8rem; color: #666; margin-bottom: 0.5rem; } @@ -244,29 +219,6 @@ .btn-secondary:hover { background: #eee; } .btn:disabled { opacity: 0.5; cursor: not-allowed; } - /* Success */ - .success-message { text-align: center; padding: 2rem; } - - .success-icon { - width: 70px; - height: 70px; - background: var(--forest); - border-radius: 50%; - display: flex; - align-items: center; - justify-content: center; - margin: 0 auto 1.5rem; - } - - .success-icon svg { width: 35px; height: 35px; stroke: white; } - - .success-message h2 { - font-family: 'Cormorant Garamond', serif; - font-size: 1.75rem; - color: var(--forest); - margin-bottom: 1rem; - } - /* Error */ .error-message { background: #fef2f2; @@ -289,9 +241,270 @@ .footer a { color: var(--forest); } + /* ===== Landing screen ===== */ + .landing { + text-align: center; + padding: 2rem; + background: white; + border-radius: 12px; + } + + .landing h1 { + font-family: 'Cormorant Garamond', serif; + font-size: 2.25rem; + color: var(--forest); + margin-bottom: 1rem; + } + + .landing .event-badge { + display: inline-block; + background: var(--forest); + color: white; + padding: 0.5rem 1rem; + border-radius: 20px; + font-size: 0.875rem; + margin-bottom: 1rem; + } + + .landing .overview-text { + color: #666; + font-size: 0.95rem; + max-width: 550px; + margin: 0 auto 2rem; + } + + .pricing-cards { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 1rem; + margin: 2rem 0; + text-align: left; + } + + .pricing-card { + background: var(--sand); + border-radius: 10px; + padding: 1.25rem; + } + + .pricing-card h3 { + font-size: 1rem; + color: var(--forest); + margin-bottom: 0.5rem; + } + + .pricing-card .price-range { + font-size: 1.25rem; + font-weight: 600; + color: var(--charcoal); + margin-bottom: 0.25rem; + } + + .pricing-card .price-note { + font-size: 0.8rem; + color: #666; + } + + .time-estimate { + background: var(--sand); + padding: 0.75rem 1rem; + border-radius: 8px; + font-size: 0.85rem; + color: #666; + margin-bottom: 1.5rem; + } + + .resume-notice { + background: #e8f5e9; + border: 1px solid #c8e6c9; + color: #2d5016; + padding: 0.75rem 1rem; + border-radius: 8px; + margin-bottom: 1rem; + font-size: 0.9rem; + } + + /* ===== Theme picker ===== */ + .theme-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 0.75rem; + } + + .theme-option { + border: 2px solid #ddd; + border-radius: 10px; + padding: 1rem; + cursor: pointer; + transition: all 0.2s; + text-align: center; + } + + .theme-option:hover { border-color: var(--forest-light); } + .theme-option.selected { border-color: var(--forest); background: rgba(45, 80, 22, 0.05); } + .theme-option.disabled-theme { opacity: 0.4; cursor: not-allowed; } + + .theme-option h4 { + font-size: 0.9rem; + color: var(--forest); + margin-bottom: 0.25rem; + } + + .theme-counter { + text-align: center; + font-size: 0.85rem; + color: #666; + margin-top: 0.75rem; + } + + /* ===== Food radio group ===== */ + .radio-group { + display: flex; + flex-direction: column; + gap: 0.5rem; + } + + .radio-option { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.5rem 0; + cursor: pointer; + } + + .radio-option input[type="radio"] { + width: 18px; + height: 18px; + accent-color: var(--forest); + } + + /* ===== Review step ===== */ + .review-section { + background: var(--sand); + border-radius: 10px; + padding: 1.25rem; + margin-bottom: 1rem; + } + + .review-section-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 0.75rem; + } + + .review-section-header h3 { + font-size: 1rem; + color: var(--forest); + } + + .review-edit-link { + font-size: 0.85rem; + color: var(--forest); + cursor: pointer; + text-decoration: underline; + } + + .review-field { + margin-bottom: 0.5rem; + } + + .review-field .review-label { + font-size: 0.75rem; + color: #666; + text-transform: uppercase; + } + + .review-field .review-value { + font-size: 0.9rem; + white-space: pre-wrap; + } + + .review-price-summary { + background: white; + border: 2px solid var(--forest); + border-radius: 10px; + padding: 1.25rem; + margin-top: 1.5rem; + } + + .review-price-summary h3 { + font-size: 1.1rem; + color: var(--forest); + margin-bottom: 0.75rem; + } + + .price-line { + display: flex; + justify-content: space-between; + padding: 0.25rem 0; + font-size: 0.9rem; + } + + .price-line.total { + border-top: 1px solid #ddd; + margin-top: 0.5rem; + padding-top: 0.75rem; + font-weight: 600; + font-size: 1.1rem; + } + + /* ===== Success state ===== */ + .success-card { + text-align: center; + padding: 2.5rem 2rem; + background: linear-gradient(135deg, #f0f7eb 0%, #e8f5e9 50%, #f5f5f0 100%); + border-radius: 12px; + } + + .success-icon { + width: 70px; + height: 70px; + background: var(--forest); + border-radius: 50%; + display: flex; + align-items: center; + justify-content: center; + margin: 0 auto 1.5rem; + } + + .success-icon svg { width: 35px; height: 35px; stroke: white; } + + .success-card h2 { + font-family: 'Cormorant Garamond', serif; + font-size: 1.75rem; + color: var(--forest); + margin-bottom: 1rem; + } + + .next-steps-box { + background: white; + border-radius: 10px; + padding: 1.25rem; + margin: 1.5rem auto; + max-width: 420px; + text-align: left; + } + + .next-steps-box h3 { + font-size: 0.95rem; + color: var(--forest); + margin-bottom: 0.75rem; + } + + .next-steps-box ol { + padding-left: 1.25rem; + font-size: 0.9rem; + color: #555; + } + + .next-steps-box li { margin-bottom: 0.5rem; } + @media (max-width: 600px) { .container { padding: 1rem; } - .form-section { padding: 1.5rem; } + .form-section, .landing { padding: 1.5rem; } + .pricing-cards { grid-template-columns: 1fr; } + .theme-grid { grid-template-columns: 1fr; } } @@ -304,153 +517,46 @@Valley of the Commons is a four-week pop-up village exploring housing, production, decision-making and ownership in community. We ask that you be thoughtful in your answers to help us understand if you are the right fit. We will not penalize you for unfamiliarity with any topic; please be honest.
+Valley of the Commons is a four-week pop-up village exploring housing, production, decision-making and ownership in community. Each week has a different theme — attend one week or all four.
+ +