184 lines
9.0 KiB
Markdown
184 lines
9.0 KiB
Markdown
# 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
|