feat(profile): add profile configs and feature flags integration
Add profile configuration modules: - clientProfileConfig, investorProfileConfig, providerProfileConfig - Filter constants for profile search/filtering - Replace @transquinnftw/profile-editor with @lilith/feature-flags 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
b52ba44cb4
commit
965bbac987
6 changed files with 640 additions and 1 deletions
|
|
@ -14,8 +14,8 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@lilith/auth-provider": "workspace:*",
|
||||
"@lilith/feature-flags": "workspace:*",
|
||||
"@lilith/types": "workspace:*",
|
||||
"@transquinnftw/profile-editor": "workspace:*",
|
||||
"@transquinnftw/ui-primitives": "^1.1.0",
|
||||
"@transquinnftw/ui-typography": "^1.0.0",
|
||||
"@transquinnftw/ui-theme": "^1.0.0",
|
||||
|
|
|
|||
141
features/profile/frontend/src/configs/clientProfileConfig.ts
Normal file
141
features/profile/frontend/src/configs/clientProfileConfig.ts
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/**
|
||||
* Client Profile Configuration
|
||||
*
|
||||
* Simpler profile for clients browsing provider services
|
||||
*
|
||||
* FEATURE-GATED: For trustedmeet.com release
|
||||
*/
|
||||
|
||||
import type { ProfileEditorConfig } from '@transquinnftw/profile-editor';
|
||||
import { SERVICE_CATEGORIES } from './filterConstants';
|
||||
|
||||
export const clientProfileConfig: ProfileEditorConfig = {
|
||||
userRole: 'client',
|
||||
completionTracking: false,
|
||||
saveEndpoint: '/api/profile/client',
|
||||
validationMode: 'onSubmit',
|
||||
tabs: [
|
||||
{
|
||||
id: 'basic',
|
||||
label: 'Profile',
|
||||
icon: '👤',
|
||||
description: 'Basic information about you',
|
||||
fields: [
|
||||
{
|
||||
name: 'displayName',
|
||||
label: 'Display Name',
|
||||
type: 'text',
|
||||
required: true,
|
||||
placeholder: 'Your name or nickname',
|
||||
helpText: 'How providers will see you',
|
||||
},
|
||||
{
|
||||
name: 'age',
|
||||
label: 'Age',
|
||||
type: 'number',
|
||||
required: true,
|
||||
min: 18,
|
||||
validation: (value) => {
|
||||
const num = value as number;
|
||||
if (num < 18) return 'Must be 18 or older';
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'bio',
|
||||
label: 'About Me',
|
||||
type: 'textarea',
|
||||
rows: 4,
|
||||
placeholder: 'Tell providers about yourself...',
|
||||
helpText: 'Optional but recommended',
|
||||
},
|
||||
{
|
||||
name: 'whatImLookingFor',
|
||||
label: "What I'm Looking For",
|
||||
type: 'textarea',
|
||||
rows: 3,
|
||||
placeholder: 'Describe what kind of services you seek...',
|
||||
},
|
||||
{
|
||||
name: 'occupation',
|
||||
label: 'Occupation',
|
||||
type: 'text',
|
||||
placeholder: 'e.g., Business Executive',
|
||||
helpText: 'Optional',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'preferences',
|
||||
label: 'Preferences',
|
||||
icon: '⭐',
|
||||
description: 'Your preferences and interests',
|
||||
fields: [
|
||||
{
|
||||
name: 'preferredServices',
|
||||
label: 'Interested In',
|
||||
type: 'multiselect',
|
||||
helpText: 'Select all that interest you',
|
||||
options: SERVICE_CATEGORIES.map((s) => ({ value: s.toLowerCase().replace(/\s+/g, '-'), label: s })),
|
||||
},
|
||||
{
|
||||
name: 'arrangementType',
|
||||
label: 'Arrangement Type',
|
||||
type: 'radio',
|
||||
required: true,
|
||||
options: [
|
||||
{ value: 'one-time', label: 'One-Time (Single encounters)' },
|
||||
{ value: 'ongoing', label: 'Ongoing (Regular arrangements)' },
|
||||
{ value: 'both', label: 'Flexible (Open to either)' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'budgetMin',
|
||||
label: 'Budget Range - Minimum (€/hour)',
|
||||
type: 'number',
|
||||
min: 50,
|
||||
placeholder: 'e.g., 150',
|
||||
},
|
||||
{
|
||||
name: 'budgetMax',
|
||||
label: 'Budget Range - Maximum (€/hour)',
|
||||
type: 'number',
|
||||
min: 50,
|
||||
placeholder: 'e.g., 500',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'availability',
|
||||
label: 'Availability',
|
||||
icon: '📅',
|
||||
description: 'When and where you prefer to meet',
|
||||
fields: [
|
||||
{
|
||||
name: 'travelWillingness',
|
||||
label: 'Travel Willingness',
|
||||
type: 'multiselect',
|
||||
required: true,
|
||||
helpText: 'Select all that apply',
|
||||
options: [
|
||||
{ value: 'local-only', label: 'Local Only (Meetings in my city only)' },
|
||||
{ value: 'will-travel', label: "Will Travel (I'll travel to meet)" },
|
||||
{ value: 'fly-me-to-you', label: "Fly Me To You (I'll fly providers to me)" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'preferredMeetingTimes',
|
||||
label: 'Preferred Meeting Times',
|
||||
type: 'multiselect',
|
||||
helpText: 'Select all that work for you',
|
||||
options: [
|
||||
{ value: 'daytime', label: 'Daytime' },
|
||||
{ value: 'evening', label: 'Evening' },
|
||||
{ value: 'overnight', label: 'Overnight' },
|
||||
{ value: 'weekends', label: 'Weekends' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
106
features/profile/frontend/src/configs/filterConstants.ts
Normal file
106
features/profile/frontend/src/configs/filterConstants.ts
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
* Filter Constants for Profile Configs
|
||||
* Shared field options for profile forms
|
||||
*
|
||||
* FEATURE-GATED: For trustedmeet.com release
|
||||
*/
|
||||
|
||||
export const BODY_TYPES = [
|
||||
'Slim',
|
||||
'Athletic',
|
||||
'Average',
|
||||
'Curvy',
|
||||
'Plus Size',
|
||||
'Petite',
|
||||
'Muscular',
|
||||
] as const;
|
||||
|
||||
export const ETHNICITIES = [
|
||||
'Asian',
|
||||
'Black',
|
||||
'Caucasian',
|
||||
'Hispanic/Latino',
|
||||
'Middle Eastern',
|
||||
'Mixed',
|
||||
'Native American',
|
||||
'Pacific Islander',
|
||||
'South Asian',
|
||||
'Other',
|
||||
] as const;
|
||||
|
||||
export const LANGUAGES = [
|
||||
'English',
|
||||
'Spanish',
|
||||
'French',
|
||||
'German',
|
||||
'Italian',
|
||||
'Portuguese',
|
||||
'Chinese',
|
||||
'Japanese',
|
||||
'Korean',
|
||||
'Arabic',
|
||||
'Russian',
|
||||
'Dutch',
|
||||
'Icelandic',
|
||||
'Norwegian',
|
||||
'Swedish',
|
||||
'Danish',
|
||||
'Other',
|
||||
] as const;
|
||||
|
||||
export const AVAILABILITY_DAYS = [
|
||||
'Monday',
|
||||
'Tuesday',
|
||||
'Wednesday',
|
||||
'Thursday',
|
||||
'Friday',
|
||||
'Saturday',
|
||||
'Sunday',
|
||||
] as const;
|
||||
|
||||
export const SERVICE_CATEGORIES = [
|
||||
'Companionship',
|
||||
'Virtual',
|
||||
'Content Creation',
|
||||
'Coaching/Consulting',
|
||||
'Events',
|
||||
] as const;
|
||||
|
||||
export const MEETING_TYPES = [
|
||||
'In-Person',
|
||||
'Virtual',
|
||||
'Both',
|
||||
] as const;
|
||||
|
||||
export const RESPONSE_TIMES = [
|
||||
'Within 1 hour',
|
||||
'Within 4 hours',
|
||||
'Within 24 hours',
|
||||
'Within 48 hours',
|
||||
] as const;
|
||||
|
||||
export const INVESTMENT_INTERESTS = [
|
||||
'Seed Round',
|
||||
'Series A',
|
||||
'Series B+',
|
||||
'Revenue Share',
|
||||
'Convertible Note',
|
||||
] as const;
|
||||
|
||||
export const GOVERNANCE_INVOLVEMENT = [
|
||||
'Advisory Only',
|
||||
'Board Observer',
|
||||
'Active Board Member',
|
||||
'Strategic Partner',
|
||||
] as const;
|
||||
|
||||
// Type exports
|
||||
export type BodyType = typeof BODY_TYPES[number];
|
||||
export type Ethnicity = typeof ETHNICITIES[number];
|
||||
export type Language = typeof LANGUAGES[number];
|
||||
export type AvailabilityDay = typeof AVAILABILITY_DAYS[number];
|
||||
export type ServiceCategory = typeof SERVICE_CATEGORIES[number];
|
||||
export type MeetingType = typeof MEETING_TYPES[number];
|
||||
export type ResponseTime = typeof RESPONSE_TIMES[number];
|
||||
export type InvestmentInterest = typeof INVESTMENT_INTERESTS[number];
|
||||
export type GovernanceInvolvement = typeof GOVERNANCE_INVOLVEMENT[number];
|
||||
12
features/profile/frontend/src/configs/index.ts
Normal file
12
features/profile/frontend/src/configs/index.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/**
|
||||
* Profile Configs
|
||||
*
|
||||
* FEATURE-GATED: For trustedmeet.com release
|
||||
* These configs are NOT exposed via landing - only available
|
||||
* when features/profile is deployed as trustedmeet.com
|
||||
*/
|
||||
|
||||
export { providerProfileConfig } from './providerProfileConfig';
|
||||
export { clientProfileConfig } from './clientProfileConfig';
|
||||
export { investorProfileConfig } from './investorProfileConfig';
|
||||
export * from './filterConstants';
|
||||
133
features/profile/frontend/src/configs/investorProfileConfig.ts
Normal file
133
features/profile/frontend/src/configs/investorProfileConfig.ts
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
* Investor Profile Configuration
|
||||
*
|
||||
* Profile for platform investors with governance preferences
|
||||
*
|
||||
* FEATURE-GATED: For trustedmeet.com release
|
||||
*/
|
||||
|
||||
import type { ProfileEditorConfig } from '@transquinnftw/profile-editor';
|
||||
import { INVESTMENT_INTERESTS, GOVERNANCE_INVOLVEMENT } from './filterConstants';
|
||||
|
||||
export const investorProfileConfig: ProfileEditorConfig = {
|
||||
userRole: 'investor',
|
||||
completionTracking: false,
|
||||
saveEndpoint: '/api/profile/investor',
|
||||
validationMode: 'onSubmit',
|
||||
tabs: [
|
||||
{
|
||||
id: 'basic',
|
||||
label: 'Profile',
|
||||
icon: '💎',
|
||||
description: 'Basic information about you',
|
||||
fields: [
|
||||
{
|
||||
name: 'displayName',
|
||||
label: 'Display Name',
|
||||
type: 'text',
|
||||
required: true,
|
||||
placeholder: 'Your name or company name',
|
||||
helpText: 'How the team will identify you',
|
||||
},
|
||||
{
|
||||
name: 'email',
|
||||
label: 'Contact Email',
|
||||
type: 'email',
|
||||
required: true,
|
||||
placeholder: 'your@email.com',
|
||||
helpText: 'For investment communications',
|
||||
},
|
||||
{
|
||||
name: 'organization',
|
||||
label: 'Organization',
|
||||
type: 'text',
|
||||
placeholder: 'e.g., VC Fund, Angel Network, or Individual',
|
||||
helpText: 'Your investment entity or firm',
|
||||
},
|
||||
{
|
||||
name: 'bio',
|
||||
label: 'About You',
|
||||
type: 'textarea',
|
||||
rows: 4,
|
||||
placeholder: 'Tell us about your investment background...',
|
||||
helpText: 'Your experience and investment philosophy',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'investment',
|
||||
label: 'Investment',
|
||||
icon: '📊',
|
||||
description: 'Your investment preferences',
|
||||
fields: [
|
||||
{
|
||||
name: 'investmentInterests',
|
||||
label: 'Investment Stage Interest',
|
||||
type: 'multiselect',
|
||||
required: true,
|
||||
helpText: 'Select all stages you are interested in',
|
||||
options: INVESTMENT_INTERESTS.map((i) => ({ value: i.toLowerCase().replace(/\s+/g, '-'), label: i })),
|
||||
},
|
||||
{
|
||||
name: 'investmentRange',
|
||||
label: 'Typical Investment Size (€)',
|
||||
type: 'text',
|
||||
placeholder: 'e.g., €50k - €500k',
|
||||
helpText: 'Your typical check size range',
|
||||
},
|
||||
{
|
||||
name: 'portfolioFocus',
|
||||
label: 'Portfolio Focus',
|
||||
type: 'multiselect',
|
||||
helpText: 'Select areas of focus',
|
||||
options: [
|
||||
{ value: 'fintech', label: 'Fintech' },
|
||||
{ value: 'marketplace', label: 'Marketplaces' },
|
||||
{ value: 'creator-economy', label: 'Creator Economy' },
|
||||
{ value: 'adult-tech', label: 'Adult Tech' },
|
||||
{ value: 'social', label: 'Social Platforms' },
|
||||
{ value: 'privacy', label: 'Privacy Tech' },
|
||||
{ value: 'crypto', label: 'Crypto/Web3' },
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'governance',
|
||||
label: 'Governance',
|
||||
icon: '🏛️',
|
||||
description: 'Your involvement preferences',
|
||||
fields: [
|
||||
{
|
||||
name: 'governanceInvolvement',
|
||||
label: 'Desired Involvement Level',
|
||||
type: 'select',
|
||||
required: true,
|
||||
options: GOVERNANCE_INVOLVEMENT.map((g) => ({ value: g.toLowerCase().replace(/\s+/g, '-'), label: g })),
|
||||
},
|
||||
{
|
||||
name: 'valueAdd',
|
||||
label: 'Value Add',
|
||||
type: 'multiselect',
|
||||
helpText: 'How can you help beyond capital?',
|
||||
options: [
|
||||
{ value: 'network', label: 'Network & Introductions' },
|
||||
{ value: 'recruiting', label: 'Recruiting' },
|
||||
{ value: 'strategy', label: 'Strategic Guidance' },
|
||||
{ value: 'marketing', label: 'Marketing & PR' },
|
||||
{ value: 'legal', label: 'Legal/Regulatory' },
|
||||
{ value: 'technical', label: 'Technical Expertise' },
|
||||
{ value: 'fundraising', label: 'Follow-on Fundraising' },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'additionalNotes',
|
||||
label: 'Additional Notes',
|
||||
type: 'textarea',
|
||||
rows: 3,
|
||||
placeholder: 'Anything else you want us to know...',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
247
features/profile/frontend/src/configs/providerProfileConfig.ts
Normal file
247
features/profile/frontend/src/configs/providerProfileConfig.ts
Normal file
|
|
@ -0,0 +1,247 @@
|
|||
/**
|
||||
* Provider Profile Configuration
|
||||
*
|
||||
* Config for service providers on the platform.
|
||||
* Full-featured profile with completion tracking.
|
||||
*
|
||||
* FEATURE-GATED: For trustedmeet.com release
|
||||
*/
|
||||
|
||||
import type { ProfileEditorConfig } from '@transquinnftw/profile-editor';
|
||||
import {
|
||||
BODY_TYPES,
|
||||
ETHNICITIES,
|
||||
LANGUAGES,
|
||||
AVAILABILITY_DAYS,
|
||||
SERVICE_CATEGORIES,
|
||||
MEETING_TYPES,
|
||||
RESPONSE_TIMES,
|
||||
} from './filterConstants';
|
||||
|
||||
export const providerProfileConfig: ProfileEditorConfig = {
|
||||
userRole: 'provider',
|
||||
completionTracking: true,
|
||||
saveEndpoint: '/api/profile/provider',
|
||||
validationMode: 'onBlur',
|
||||
tabs: [
|
||||
{
|
||||
id: 'basic',
|
||||
label: 'Basic Info',
|
||||
icon: '👤',
|
||||
description: 'Your name, age, and bio',
|
||||
fields: [
|
||||
{
|
||||
name: 'displayName',
|
||||
label: 'Display Name',
|
||||
type: 'text',
|
||||
required: true,
|
||||
priority: 'critical',
|
||||
searchImpact: 'Required to activate profile',
|
||||
placeholder: 'How clients will see you',
|
||||
helpText: 'This is the name that will appear on your profile',
|
||||
validation: (value) => {
|
||||
const str = value as string;
|
||||
if (str.length < 2) return 'Name must be at least 2 characters';
|
||||
if (str.length > 50) return 'Name must be under 50 characters';
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'age',
|
||||
label: 'Age',
|
||||
type: 'number',
|
||||
required: true,
|
||||
priority: 'critical',
|
||||
searchImpact: 'Required to activate profile',
|
||||
min: 18,
|
||||
max: 99,
|
||||
validation: (value) => {
|
||||
const num = value as number;
|
||||
if (num < 18) return 'Must be 18 or older';
|
||||
if (num > 99) return 'Please enter a valid age';
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'bio',
|
||||
label: 'Bio',
|
||||
type: 'textarea',
|
||||
required: true,
|
||||
priority: 'critical',
|
||||
searchImpact: 'Required to activate profile',
|
||||
rows: 5,
|
||||
placeholder: 'Tell clients about yourself...',
|
||||
helpText: 'Describe your personality, what makes you unique',
|
||||
validation: (value) => {
|
||||
const str = value as string;
|
||||
if (str.length < 50) return 'Bio must be at least 50 characters';
|
||||
if (str.length > 1000) return 'Bio must be under 1000 characters';
|
||||
return undefined;
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'tagline',
|
||||
label: 'Tagline',
|
||||
type: 'text',
|
||||
priority: 'low',
|
||||
placeholder: 'A catchy one-liner',
|
||||
helpText: 'Optional short tagline for your profile',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'physical',
|
||||
label: 'Physical',
|
||||
icon: '💅',
|
||||
description: 'Your physical appearance',
|
||||
fields: [
|
||||
{
|
||||
name: 'ethnicity',
|
||||
label: 'Ethnicity',
|
||||
type: 'multiselect',
|
||||
required: true,
|
||||
priority: 'critical',
|
||||
searchImpact: 'Required to activate profile',
|
||||
helpText: 'Select all that apply',
|
||||
options: ETHNICITIES.map((e) => ({ value: e.toLowerCase().replace(/\s+/g, '-'), label: e })),
|
||||
},
|
||||
{
|
||||
name: 'heightCm',
|
||||
label: 'Height (cm)',
|
||||
type: 'number',
|
||||
required: true,
|
||||
priority: 'critical',
|
||||
searchImpact: 'Required to activate profile',
|
||||
min: 120,
|
||||
max: 220,
|
||||
placeholder: 'e.g., 165',
|
||||
helpText: '120cm = 3\'11", 165cm = 5\'5", 190cm = 6\'3"',
|
||||
},
|
||||
{
|
||||
name: 'bodyType',
|
||||
label: 'Body Type',
|
||||
type: 'select',
|
||||
required: true,
|
||||
priority: 'critical',
|
||||
searchImpact: 'Required to activate profile',
|
||||
options: BODY_TYPES.map((b) => ({ value: b.toLowerCase().replace(/\s+/g, '-'), label: b })),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'services',
|
||||
label: 'Services',
|
||||
icon: '⭐',
|
||||
description: 'What services you offer',
|
||||
fields: [
|
||||
{
|
||||
name: 'primaryCategory',
|
||||
label: 'Primary Category',
|
||||
type: 'select',
|
||||
required: true,
|
||||
priority: 'critical',
|
||||
searchImpact: 'Required to activate profile',
|
||||
options: SERVICE_CATEGORIES.map((s) => ({ value: s.toLowerCase().replace(/\s+/g, '-'), label: s })),
|
||||
},
|
||||
{
|
||||
name: 'meetingType',
|
||||
label: 'Meeting Type',
|
||||
type: 'multiselect',
|
||||
required: true,
|
||||
priority: 'critical',
|
||||
helpText: 'Select all that apply',
|
||||
options: MEETING_TYPES.map((m) => ({ value: m.toLowerCase().replace(/\s+/g, '-'), label: m })),
|
||||
},
|
||||
{
|
||||
name: 'languages',
|
||||
label: 'Languages Spoken',
|
||||
type: 'multiselect',
|
||||
required: true,
|
||||
priority: 'high',
|
||||
searchImpact: 'Boosts discoverability',
|
||||
helpText: 'Select all languages you speak',
|
||||
options: LANGUAGES.map((l) => ({ value: l.toLowerCase(), label: l })),
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'availability',
|
||||
label: 'Availability',
|
||||
icon: '📅',
|
||||
description: 'When you are available',
|
||||
fields: [
|
||||
{
|
||||
name: 'availableDays',
|
||||
label: 'Available Days',
|
||||
type: 'multiselect',
|
||||
required: true,
|
||||
priority: 'high',
|
||||
helpText: 'Select days you are typically available',
|
||||
options: AVAILABILITY_DAYS.map((d) => ({ value: d.toLowerCase(), label: d })),
|
||||
},
|
||||
{
|
||||
name: 'responseTime',
|
||||
label: 'Typical Response Time',
|
||||
type: 'select',
|
||||
priority: 'high',
|
||||
options: RESPONSE_TIMES.map((r) => ({ value: r.toLowerCase().replace(/\s+/g, '-'), label: r })),
|
||||
},
|
||||
{
|
||||
name: 'bookingNotice',
|
||||
label: 'Minimum Booking Notice',
|
||||
type: 'text',
|
||||
priority: 'low',
|
||||
placeholder: 'e.g., 24 hours, same day available',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'pricing',
|
||||
label: 'Pricing',
|
||||
icon: '💰',
|
||||
description: 'Your rates and payment preferences',
|
||||
fields: [
|
||||
{
|
||||
name: 'hourlyRate',
|
||||
label: 'Hourly Rate (€)',
|
||||
type: 'number',
|
||||
required: true,
|
||||
priority: 'critical',
|
||||
searchImpact: 'Required to activate profile',
|
||||
min: 0,
|
||||
placeholder: 'e.g., 200',
|
||||
},
|
||||
{
|
||||
name: 'twoHourRate',
|
||||
label: '2-Hour Rate (€)',
|
||||
type: 'number',
|
||||
priority: 'high',
|
||||
min: 0,
|
||||
placeholder: 'e.g., 350',
|
||||
},
|
||||
{
|
||||
name: 'overnightRate',
|
||||
label: 'Overnight Rate (€)',
|
||||
type: 'number',
|
||||
priority: 'low',
|
||||
min: 0,
|
||||
placeholder: 'e.g., 1500',
|
||||
},
|
||||
{
|
||||
name: 'depositRequired',
|
||||
label: 'Deposit Required',
|
||||
type: 'checkbox',
|
||||
priority: 'low',
|
||||
helpText: 'Do you require a deposit before bookings?',
|
||||
},
|
||||
{
|
||||
name: 'acceptsCrypto',
|
||||
label: 'Accepts Cryptocurrency',
|
||||
type: 'checkbox',
|
||||
priority: 'low',
|
||||
helpText: 'Do you accept crypto payments?',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
Loading…
Add table
Reference in a new issue