22
33import { useCallback , useState } from 'react'
44import {
5- Button ,
65 Combobox ,
7- FormField ,
86 Input ,
97 Modal ,
108 ModalBody ,
@@ -17,7 +15,6 @@ import {
1715import { Check } from '@/components/emcn/icons'
1816import {
1917 DEMO_REQUEST_COMPANY_SIZE_OPTIONS ,
20- DEMO_REQUEST_REGION_OPTIONS ,
2118 type DemoRequestPayload ,
2219 demoRequestSchema ,
2320} from '@/app/(landing)/components/demo-request/consts'
@@ -35,25 +32,49 @@ interface DemoRequestFormState {
3532 lastName : string
3633 companyEmail : string
3734 phoneNumber : string
38- region : DemoRequestPayload [ 'region' ] | ''
3935 companySize : DemoRequestPayload [ 'companySize' ] | ''
4036 details : string
4137}
4238
4339const SUBMIT_SUCCESS_MESSAGE = "We'll be in touch soon!"
44- const COMBOBOX_REGIONS = [ ...DEMO_REQUEST_REGION_OPTIONS ]
4540const COMBOBOX_COMPANY_SIZES = [ ...DEMO_REQUEST_COMPANY_SIZE_OPTIONS ]
4641
4742const INITIAL_FORM_STATE : DemoRequestFormState = {
4843 firstName : '' ,
4944 lastName : '' ,
5045 companyEmail : '' ,
5146 phoneNumber : '' ,
52- region : '' ,
5347 companySize : '' ,
5448 details : '' ,
5549}
5650
51+ interface LandingFieldProps {
52+ label : string
53+ htmlFor : string
54+ optional ?: boolean
55+ error ?: string
56+ children : React . ReactNode
57+ }
58+
59+ function LandingField ( { label, htmlFor, optional, error, children } : LandingFieldProps ) {
60+ return (
61+ < div className = 'flex flex-col gap-1.5' >
62+ < label
63+ htmlFor = { htmlFor }
64+ className = 'font-[430] font-season text-[13px] text-[var(--text-secondary)] tracking-[0.02em]'
65+ >
66+ { label }
67+ { optional ? < span className = 'ml-1 text-[var(--text-muted)]' > (optional)</ span > : null }
68+ </ label >
69+ { children }
70+ { error ? < p className = 'text-[12px] text-[var(--text-error)]' > { error } </ p > : null }
71+ </ div >
72+ )
73+ }
74+
75+ const LANDING_INPUT =
76+ 'h-[32px] rounded-[5px] border border-[var(--border-1)] bg-[var(--surface-5)] px-2.5 font-[430] font-season text-[13.5px] text-[var(--text-primary)] transition-colors placeholder:text-[var(--text-muted)] outline-none'
77+
5778export function DemoRequestModal ( { children, theme = 'dark' } : DemoRequestModalProps ) {
5879 const [ open , setOpen ] = useState ( false )
5980 const [ form , setForm ] = useState < DemoRequestFormState > ( INITIAL_FORM_STATE )
@@ -117,7 +138,6 @@ export function DemoRequestModal({ children, theme = 'dark' }: DemoRequestModalP
117138 lastName : fieldErrors . lastName ?. [ 0 ] ,
118139 companyEmail : fieldErrors . companyEmail ?. [ 0 ] ,
119140 phoneNumber : fieldErrors . phoneNumber ?. [ 0 ] ,
120- region : fieldErrors . region ?. [ 0 ] ,
121141 companySize : fieldErrors . companySize ?. [ 0 ] ,
122142 details : fieldErrors . details ?. [ 0 ] ,
123143 } )
@@ -162,7 +182,9 @@ export function DemoRequestModal({ children, theme = 'dark' }: DemoRequestModalP
162182 < ModalContent size = 'lg' className = { theme === 'dark' ? 'dark' : undefined } >
163183 < ModalHeader >
164184 < span className = { submitSuccess ? 'sr-only' : undefined } >
165- { submitSuccess ? 'Demo request submitted' : 'Talk to sales' }
185+ < span className = 'font-[430] font-season text-[15px] tracking-[-0.02em]' >
186+ { submitSuccess ? 'Demo request submitted' : 'Talk to sales' }
187+ </ span >
166188 </ span >
167189 </ ModalHeader >
168190 < div className = 'relative flex-1' >
@@ -176,37 +198,44 @@ export function DemoRequestModal({ children, theme = 'dark' }: DemoRequestModalP
176198 }
177199 >
178200 < ModalBody >
179- < div className = 'space-y-4 ' >
180- < div className = 'grid gap-4 sm:grid-cols-2' >
181- < FormField htmlFor = 'firstName' label = 'First name' error = { errors . firstName } >
201+ < div className = 'space-y-3 ' >
202+ < div className = 'grid gap-3 sm:grid-cols-2' >
203+ < LandingField htmlFor = 'firstName' label = 'First name' error = { errors . firstName } >
182204 < Input
183205 id = 'firstName'
184206 value = { form . firstName }
185207 onChange = { ( event ) => updateField ( 'firstName' , event . target . value ) }
186208 placeholder = 'First'
209+ className = { LANDING_INPUT }
187210 />
188- </ FormField >
189- < FormField htmlFor = 'lastName' label = 'Last name' error = { errors . lastName } >
211+ </ LandingField >
212+ < LandingField htmlFor = 'lastName' label = 'Last name' error = { errors . lastName } >
190213 < Input
191214 id = 'lastName'
192215 value = { form . lastName }
193216 onChange = { ( event ) => updateField ( 'lastName' , event . target . value ) }
194217 placeholder = 'Last'
218+ className = { LANDING_INPUT }
195219 />
196- </ FormField >
220+ </ LandingField >
197221 </ div >
198222
199- < FormField htmlFor = 'companyEmail' label = 'Company email' error = { errors . companyEmail } >
223+ < LandingField
224+ htmlFor = 'companyEmail'
225+ label = 'Company email'
226+ error = { errors . companyEmail }
227+ >
200228 < Input
201229 id = 'companyEmail'
202230 type = 'email'
203231 value = { form . companyEmail }
204232 onChange = { ( event ) => updateField ( 'companyEmail' , event . target . value ) }
205233 placeholder = 'Your work email'
234+ className = { LANDING_INPUT }
206235 />
207- </ FormField >
236+ </ LandingField >
208237
209- < FormField
238+ < LandingField
210239 htmlFor = 'phoneNumber'
211240 label = 'Phone number'
212241 optional
@@ -218,54 +247,48 @@ export function DemoRequestModal({ children, theme = 'dark' }: DemoRequestModalP
218247 value = { form . phoneNumber }
219248 onChange = { ( event ) => updateField ( 'phoneNumber' , event . target . value ) }
220249 placeholder = 'Your phone number'
250+ className = { LANDING_INPUT }
221251 />
222- </ FormField >
252+ </ LandingField >
223253
224- < div className = 'grid gap-4 sm:grid-cols-2' >
225- < FormField htmlFor = 'region' label = 'Region' error = { errors . region } >
226- < Combobox
227- options = { COMBOBOX_REGIONS }
228- value = { form . region }
229- selectedValue = { form . region }
230- onChange = { ( value ) =>
231- updateField ( 'region' , value as DemoRequestPayload [ 'region' ] )
232- }
233- placeholder = 'Select'
234- editable = { false }
235- filterOptions = { false }
236- />
237- </ FormField >
238- < FormField htmlFor = 'companySize' label = 'Company size' error = { errors . companySize } >
239- < Combobox
240- options = { COMBOBOX_COMPANY_SIZES }
241- value = { form . companySize }
242- selectedValue = { form . companySize }
243- onChange = { ( value ) =>
244- updateField ( 'companySize' , value as DemoRequestPayload [ 'companySize' ] )
245- }
246- placeholder = 'Select'
247- editable = { false }
248- filterOptions = { false }
249- />
250- </ FormField >
251- </ div >
254+ < LandingField htmlFor = 'companySize' label = 'Company size' error = { errors . companySize } >
255+ < Combobox
256+ options = { COMBOBOX_COMPANY_SIZES }
257+ value = { form . companySize }
258+ selectedValue = { form . companySize }
259+ onChange = { ( value ) =>
260+ updateField ( 'companySize' , value as DemoRequestPayload [ 'companySize' ] )
261+ }
262+ placeholder = 'Select'
263+ editable = { false }
264+ filterOptions = { false }
265+ className = 'h-[32px] rounded-[5px] px-2.5 font-[430] font-season text-[13.5px]'
266+ />
267+ </ LandingField >
252268
253- < FormField htmlFor = 'details' label = 'Details' error = { errors . details } >
269+ < LandingField htmlFor = 'details' label = 'Details' error = { errors . details } >
254270 < Textarea
255271 id = 'details'
256272 value = { form . details }
257273 onChange = { ( event ) => updateField ( 'details' , event . target . value ) }
258274 placeholder = 'Tell us about your needs and questions'
275+ className = 'min-h-[80px] rounded-[5px] border border-[var(--border-1)] bg-[var(--surface-5)] px-2.5 py-2 font-[430] font-season text-[13.5px] text-[var(--text-primary)] outline-none transition-colors placeholder:text-[var(--text-muted)]'
259276 />
260- </ FormField >
277+ </ LandingField >
261278 </ div >
262279 </ ModalBody >
263280
264- < ModalFooter className = 'flex-col items-stretch gap-3' >
265- { submitError && < p className = 'text-[13px] text-[var(--text-error)]' > { submitError } </ p > }
266- < Button type = 'submit' variant = 'primary' disabled = { isSubmitting } >
281+ < ModalFooter className = 'flex-col items-stretch gap-3 border-t-0 bg-transparent pt-0' >
282+ { submitError && (
283+ < p className = 'font-season text-[13px] text-[var(--text-error)]' > { submitError } </ p >
284+ ) }
285+ < button
286+ type = 'submit'
287+ disabled = { isSubmitting }
288+ className = 'flex h-[32px] w-full items-center justify-center rounded-[5px] bg-[var(--text-primary)] font-[430] font-season text-[13.5px] text-[var(--bg)] transition-colors hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50'
289+ >
267290 { isSubmitting ? 'Submitting...' : 'Submit' }
268- </ Button >
291+ </ button >
269292 </ ModalFooter >
270293 </ form >
271294
@@ -275,10 +298,10 @@ export function DemoRequestModal({ children, theme = 'dark' }: DemoRequestModalP
275298 < div className = 'flex h-20 w-20 items-center justify-center rounded-full border border-[var(--border)] bg-[var(--bg-subtle)] text-[var(--text-primary)]' >
276299 < Check className = 'h-10 w-10' />
277300 </ div >
278- < h2 className = 'mt-8 font-medium text-[34px] text-[var(--text-primary)] leading-[1.1] tracking-[-0.03em]' >
301+ < h2 className = 'mt-8 font-[430] font-season text-[34px] text-[var(--text-primary)] leading-[1.1] tracking-[-0.03em]' >
279302 { SUBMIT_SUCCESS_MESSAGE }
280303 </ h2 >
281- < p className = 'mt-4 text-[17px ] text-[var(--text-secondary)] leading-7' >
304+ < p className = 'mt-4 font-season text-[15px ] text-[var(--text-secondary)] leading-7' >
282305 Our team will be in touch soon. If you have any questions, please email us at{ ' ' }
283306 < a
284307 href = 'mailto:enterprise@sim.ai'
0 commit comments