6b99bcea7f
## Summary - Add a dedicated **Experience** step to the partner apply wizard (milestones, ≥200-char narrative, proof URL) before commercials - Stop collecting `applicationNotes`; rename Expertise chrome away from “experience” - Replace the post-submit Cal.com embed with a review-and-reach-out thank-you so unqualified inbound no longer books intros automatically **Companion PR (app):** #23224 — Partner schema, submit persistence, triage views, Tally CSV mapper (`twenty-partners` v1.4.0). Land the app PR with or before this one. ## Test plan - [ ] Open apply modal: wizard order is identity → profile → expertise → experience → commercials - [ ] Experience step blocks continue without ≥1 milestone, narrative ≥200 chars, and a valid https URL - [ ] Submit creates/updates Partner with the three experience fields (with #23224 deployed) - [ ] Success screen has no Cal embed / book-later CTA - [ ] `npx jest --config=jest.config.mjs partner-application` passes locally (71 tests) --------- Co-authored-by: Abdullah <125115953+mabdullahabaid@users.noreply.github.com>
53 lines
2.1 KiB
TypeScript
53 lines
2.1 KiB
TypeScript
import { INITIAL_PARTNER_APPLICATION_STATE } from './partner-application-state';
|
|
import { validatePartnerApplicationStep } from './validate-partner-application-step';
|
|
|
|
const validExperienceNotes =
|
|
'Built a custom Twenty app for a property-management client, modeled leases and ' +
|
|
'tenants as data models, automated renewal workflows, and shipped a front component ' +
|
|
'for the broker dashboard with role-based views.';
|
|
|
|
describe('validatePartnerApplicationStep', () => {
|
|
it('requires experience milestones, narrative, and proof URL on Experience', () => {
|
|
const errors = validatePartnerApplicationStep({
|
|
...INITIAL_PARTNER_APPLICATION_STATE,
|
|
stepIndex: 3,
|
|
});
|
|
expect(errors.twentyExperience).toBe('required');
|
|
expect(errors.twentyExperienceNotes).toBe('required');
|
|
expect(errors.twentyExperienceProofLink).toBe('required');
|
|
});
|
|
|
|
it('rejects a narrative under 200 characters on Experience', () => {
|
|
const errors = validatePartnerApplicationStep({
|
|
...INITIAL_PARTNER_APPLICATION_STATE,
|
|
stepIndex: 3,
|
|
twentyExperience: ['WORKFLOWS'],
|
|
twentyExperienceNotes: 'Too short for a real implementation narrative.',
|
|
twentyExperienceProofLink: 'https://www.loom.com/share/example',
|
|
});
|
|
expect(errors.twentyExperienceNotes).toBe('too_short');
|
|
});
|
|
|
|
it('rejects an invalid proof URL on Experience', () => {
|
|
const errors = validatePartnerApplicationStep({
|
|
...INITIAL_PARTNER_APPLICATION_STATE,
|
|
stepIndex: 3,
|
|
twentyExperience: ['CUSTOM_APPS'],
|
|
twentyExperienceNotes: validExperienceNotes,
|
|
twentyExperienceProofLink: 'not-a-url',
|
|
});
|
|
expect(errors.twentyExperienceProofLink).toBe('invalid_url');
|
|
});
|
|
|
|
it('accepts a complete Experience step', () => {
|
|
const errors = validatePartnerApplicationStep({
|
|
...INITIAL_PARTNER_APPLICATION_STATE,
|
|
stepIndex: 3,
|
|
twentyExperience: ['CUSTOM_APPS', 'DATA_MODELS'],
|
|
twentyExperienceNotes: validExperienceNotes,
|
|
twentyExperienceProofLink: 'https://www.loom.com/share/example',
|
|
});
|
|
expect(errors).toEqual({});
|
|
});
|
|
});
|