Add a field to the lead form (end-to-end)
Goal: add a new field — we’ll use occupation (the buyer’s job, a free-text field) — to the
broker “New Deal” form, and have it travel all the way to Dynamics 365. Read
Broker submits a lead first if the flow isn’t fresh.
The path a field takes
Section titled “The path a field takes”New Deal form ──▶ NewDealFormInterface ──▶ POST /api/broker/leads (frontend) │ ▼ SubmitLeadRequest (validate) ──▶ SubmitNewLead (forward) (backend) │ ▼ SubmitNewLeadRequest (validate) ──▶ SubmitNewLeadRequestMapper (crms-middleware) │ occupation ⟶ <dynamics field> ▼ Azure Logic App ──▶ Dynamics 365You edit three request classes, one mapper, and the form — and you touch i18n. Below, per repo.
Repo frontend, app apps/orascom-broker-app. Edit exactly these:
- src/definitions/interfaces/inputs/new-deal.ts two interfaces
- src/pages/new-deal/new-deal.tsx form + payload
- public/locales/en/translation.json labels
- public/locales/ar/translation.json labels (partial stub — add here too)
-
new-deal.ts— add the field to both interfaces:// NewDealInputInterface (Formik value shape — camelCase)occupation?: string;// NewDealFormInterface (API request body — snake_case, the backend's field name)occupation?: string;For a single word like
occupationthe two names match. For a multi-word field they diverge — the Formik interface stays camelCase (jobTitle) while the request interface uses snake_case (job_title) — and you map between them insubmitHandler. -
new-deal.tsx— four edits insideNewDeal():initialValues(~line 378):occupation: ''- Add a
<Field>block inside<Form>(copy the “First name” block, ~397–414), with a<label>{t('occupation')}</label>and<ErrorMessage name="occupation" />. schema(Yup, ~206): add a rule if needed, e.g.occupation: yup.string()(required fields also gate the submit button via!isValid).submitHandlermappedData(~247–293): map it into the body —occupation: values.occupation(guard it likebudget/phone_2if it can be empty).
-
i18n — add
occupation(label + placeholder + any validation message) to bothen/translation.jsonandar/translation.json. Arabic is a partial stub, so if you skip it the label renders in English even in Arabic mode.
Repo backend. The minimal case is one file:
-
app/Http/Requests/Broker/SubmitLeadRequest.php— add the field + rule torules():'occupation' => ['nullable', 'string'],That’s it for send-to-CRM:
SubmitNewLead::prepareRequestDataforwards the entire validated array under the same keys, sooccupationreaches the middleware automatically. -
Only if the field must be stored locally (rare — the local
user_requeststable is a thin audit record, not a copy of the lead):app/Models/UserRequest.php— add the column to$fillable(fields not in$fillableare silently dropped bycreate()).- Add a migration under
database/migrations/(pattern:2024_11_20_113757_add_country_code_column_to_user_requests_table.php).
-
Parity — if the field is cross-persona, mirror it in the shopper request (
app/Http/Requests/Shopper/SubmitLeadRequest.php+ShopperSubmitNewLead) and the sales-man request (app/Http/Requests/SalesMan/Lead/SubmitLeadRequest.php+SalesMan\Lead\SubmitNewLead).
Repo crms-middleware. Two files — validate the field, then map it to a Dynamics field name:
-
app/Http/Requests/Api/Portals/Broker/SubmitNewLeadRequest.php— add the unified key torules(). Required:$request->validated()drops anything not declared here. -
app/Mapper/SubmitNewLeadRequestMapper.php— add one entry to theDictschema:'jobtitle' => new Str('occupation'), // 'jobtitle' ⟵ confirm with CRMThe array key is the Dynamics field name (agree it with the CRM team); the constructor arg is the unified request key. Use
Decimalfor money-like numbers (asclientbudget),Strotherwise. -
No client/config change — the same Logic App URL (
LEAD_CRM_SUBMIT_NEW_LEAD_URL) is reused. Only touchconfig/services.php/env if you point at a different upstream.
Verify it end-to-end
Section titled “Verify it end-to-end”- Lint + type-check the frontend:
yarn nx lint orascom-broker-appandtsc -p apps/orascom-broker-app/tsconfig.app.json --noEmit(plaintsc --noEmitchecks nothing in this Nx app). - Backend: add/adjust a Feature test under
tests/Feature/Api/Broker/…(happy + validation + auth-failure), runphp artisan test. - Manually: run the broker app (
yarn start:broker, port 4201), submit a lead with the new field, and confirm the value reaches the CRM. If you can’t see it land in Dynamics, that’s the Logic App / field-name contract — go back to the CRM team. - Contracts: update
backend/docs/openapi.yamlandcrms-middleware/docs/portals-openapi.yml.
