# Custom Forms Feature - Implementation Plan ## Context Currently, Talk Proposals and Sponsorship Enquiries use Frappe Web Forms, and Event Feedback has a minimal DocType with no frontend form. We want to replace these with dashboard-based Vue forms using a shared `BaseCustomEventForm.vue` that renders doctype fields + Pohodex Event Manager Custom Fields, with a common success state. This removes the dependency on Frappe Web Forms and gives us full control over UX. ## Architecture ``` Routes: /dashboard/events/:eventRoute/feedback → FeedbackForm.vue /dashboard/events/:eventRoute/propose-talk → ProposeTalkForm.vue /dashboard/events/:eventRoute/enquire-sponsorship → EnquireSponsorshipForm.vue Components: FeedbackForm.vue ──────────┐ ProposeTalkForm.vue ────────┼──► BaseCustomEventForm.vue EnquireSponsorshipForm.vue ─┘ │ ├── CustomFieldInput.vue (reused) ├── CustomFieldsSection.vue (reused) └── FormSuccess.vue (new, inline success state) ``` --- ## Phase 1: Backend DocType Schema Updates ### 1.1 Update Event Feedback DocType **File:** `event_manager/events/doctype/event_feedback/event_feedback.json` - Add only `additional_fields` (Table → Additional Field) — keep the DocType minimal for now - Add permission: `Pohodex Event Manager User` role with `create: 1, read: 1` (if_owner) ### 1.2 Add `additional_fields` to Talk Proposal & Sponsorship Enquiry **Files:** - `event_manager/proposals/doctype/talk_proposal/talk_proposal.json` — add `additional_fields` (Table → Additional Field) - `event_manager/proposals/doctype/sponsorship_enquiry/sponsorship_enquiry.json` — add `additional_fields` (Table → Additional Field) Reuses existing `Additional Field` child table (`event_manager/ticketing/doctype/additional_field/`). ### 1.3 Update Pohodex Event Manager Custom Field `applied_to` options **File:** `event_manager/event_manager/doctype/buzz_custom_field/buzz_custom_field.json` - Add options: `Event Feedback`, `Talk Proposal`, `Sponsorship Enquiry` ### 1.4 Run `bench migrate` --- ## Phase 2: Backend API Endpoints **File:** `event_manager/api.py` ### 2.1 `get_custom_form_data(event_route, form_type)` - Whitelist check: `form_type` must be in `CUSTOM_FORM_CONFIG` dict - Resolve event from `event_route` - Check deadline (`talk_proposals_close_at`, `sponsorship_proposals_close_at`, none for feedback, show a nice closed message / banner if the form is closed) - Return `form_fields` (from doctype meta, excluding internal fields like `status`, `submitted_by`, `owner`, `event`), `custom_fields` (Pohodex Event Manager Custom Fields for this event + `applied_to`), `event` details, `closed` flag - we should also check if event itself is published or not, if not 404 ### 2.2 `submit_custom_form(event_route, form_type, data, custom_fields_data)` - Whitelist check on `form_type` - Auto-set: `event` from route, `submitted_by` from session user (for Talk Proposal) - Validate submitted fields against allowed fieldnames - Create doc, append `additional_fields` rows for custom field values - Return `{name, doctype}` Config dict: ```python CUSTOM_FORM_CONFIG = { "Event Feedback": { "applied_to": "Event Feedback", "exclude_fields": {"name", "owner", "creation", "modified", "modified_by", "docstatus", "idx", "additional_fields", "event"}, "auto_set": {"event": "from_route"}, "deadline_field": None, }, "Talk Proposal": { "applied_to": "Talk Proposal", "exclude_fields": {"name", "owner", "creation", "modified", "modified_by", "docstatus", "idx", "submitted_by", "status", "additional_fields", "event"}, "auto_set": {"event": "from_route", "submitted_by": "session_user"}, "deadline_field": "talk_proposals_close_at", }, "Sponsorship Enquiry": { "applied_to": "Sponsorship Enquiry", "exclude_fields": {"name", "owner", "creation", "modified", "modified_by", "docstatus", "idx", "status", "additional_fields", "event"}, "auto_set": {"event": "from_route"}, "deadline_field": "sponsorship_proposals_close_at", }, } ``` --- ## Phase 3: Frontend ### 3.1 Add routes in `dashboard/src/router.ts` Three new routes with `props: true`, marked `isPublic` but depending on weather the event has guest booking enabled or not, it should handle that ### 3.2 Create `BaseCustomEventForm.vue` **File:** `dashboard/src/components/BaseCustomEventForm.vue` **Props:** `eventRoute`, `formType`, `title`, `successTitle`, `successMessage` **Behavior:** 1. Fetch form data via `createResource` → `event_manager.api.get_custom_form_data` 2. If `closed`, show "submissions closed" message 3. Render standard fields using `CustomFieldInput.vue` (normalized to same shape) 4. Render Pohodex Event Manager Custom Fields via `CustomFieldsSection.vue` 5. Submit via `event_manager.api.submit_custom_form` 6. On success, show inline success state (no separate page) **Special field type handling** (in BaseCustomEventForm, not CustomFieldInput): - `Text Editor` → frappe-ui `TextEditor` - `Attach Image` → frappe-ui `FileUploader` (upload first, set URL on doc) - `Link` → `Autocomplete` with debounced search on linked doctype (check apps/crm on how it renders link field n the CRM frontend, you might also find other types of fields being rendered in the Field.vue of CRM) - `Table` (e.g. speakers) → List view component showing added rows + "Add" button. Clicking "Add" opens a dialog with the child table's fields. On dialog submit, row is appended. No inline editing — edit button to open the dialog again. ### 3.3 Create wrapper page components - `dashboard/src/pages/FeedbackForm.vue` — passes `form-type="Event Feedback"`, default success strings - `dashboard/src/pages/ProposeTalkForm.vue` — passes `form-type="Talk Proposal"`, default success strings - `dashboard/src/pages/EnquireSponsorshipForm.vue` — passes `form-type="Sponsorship Enquiry"`, default success strings Each is ~15 lines: just a template with `BaseCustomEventForm` and `defineProps`. Default success strings are fallbacks — event-level configured messages take priority (see 3.5). ### 3.4 Extend `CustomFieldInput.vue` (if needed) **File:** `dashboard/src/components/CustomFieldInput.vue` - May need minor extensions for `Rating` fieldtype - Complex types (Table) handled directly in `BaseCustomEventForm.vue` - Text Editor, Attach Image, Link, should be added to custom field input - in the backend the value column should be changed to `Code` type to support various values like this - The attachments should be attached to the document being created, the custom field should have the path (check File doctype) to the file ### 3.5 Configurable success messages per event **DocType change:** Add 3 markdown fields to `Pohodex Event Manager Event` DocType: - `feedback_success_message` (Markdown) - `proposal_success_message` (Markdown) - `sponsorship_success_message` (Markdown) **API:** `get_custom_form_data` returns the relevant success message field for the form type. **Frontend:** `BaseCustomEventForm.vue` uses event-configured message if set, otherwise falls back to wrapper's default props. --- ## Files Summary ### New files (6) | File | Purpose | |------|---------| | `dashboard/src/components/BaseCustomEventForm.vue` | Shared form renderer | | `dashboard/src/pages/FeedbackForm.vue` | Feedback wrapper | | `dashboard/src/pages/ProposeTalkForm.vue` | Talk proposal wrapper | | `dashboard/src/pages/EnquireSponsorshipForm.vue` | Sponsorship wrapper | ### Modified files (7) | File | Change | |------|--------| | `event_manager/events/doctype/event_feedback/event_feedback.json` | Add additional_fields + permissions | | `event_manager/proposals/doctype/talk_proposal/talk_proposal.json` | Add additional_fields table | | `event_manager/proposals/doctype/sponsorship_enquiry/sponsorship_enquiry.json` | Add additional_fields table | | `event_manager/event_manager/doctype/buzz_custom_field/buzz_custom_field.json` | Add 3 new applied_to options | | `event_manager/events/doctype/buzz_event/buzz_event.json` | Add 3 success message markdown fields | | `event_manager/api.py` | Add `get_custom_form_data` + `submit_custom_form` | | `dashboard/src/router.ts` | Add 3 routes | --- ## Implementation Order 1. DocType schema changes + `bench migrate` 2. API endpoints in `event_manager/api.py` 3. `BaseCustomEventForm.vue` 4. Three wrapper pages + router routes 5. Test each form end-to-end ## Verification - Create a Pohodex Event Manager Event with a route - Add Pohodex Event Manager Custom Fields for each `applied_to` type - Navigate to each form URL, verify fields render (standard + custom) - Submit each form, verify doc created with correct data + additional_fields - Test deadline enforcement (set `talk_proposals_close_at` to past, verify form shows closed) - Test without login → should redirect to login page