11import React from 'react' ;
2- import { Button , Badge , Form } from 'react-bootstrap' ;
2+ import { Button , Badge , Form , Offcanvas } from 'react-bootstrap' ;
33import { TopBar , Footer } from '../components/Chrome' ;
44import '../lib/image-slot.js' ;
55
6+ const PITCH_BLANK = { first : '' , last : '' , email : '' , phone : '' , kind : '' , details : '' } ;
7+ const PROJECT_KINDS = [ 'Native App' , 'Web App' , 'Web Base Project' , 'Other' ] ;
8+
69const MODELS = [
710 [
811 'Build for Equity' ,
@@ -48,7 +51,7 @@ const CRITERIA = [
4851 [ 'A Path to Revenue' , 'A named first customer or a market we can reach in the first year.' ] ,
4952] ;
5053
51- function Band ( ) {
54+ function Band ( { onPitch } ) {
5255 return (
5356 < section className = "band-dark" >
5457 < div className = "wrap d-flex flex-column gap-4 align-items-start" >
@@ -58,13 +61,7 @@ function Band() {
5861 CodeBoxx Ventures puts the studio’s delivery capacity behind products we believe in.
5962 Cash, equity, or both — the structure follows the stage you are at.
6063 </ p >
61- < Button
62- onClick = { ( ) => {
63- location . href = '/#contact' ;
64- } }
65- >
66- Pitch Your Project
67- </ Button >
64+ < Button onClick = { onPitch } > Pitch Your Project</ Button >
6865 </ div >
6966 </ section >
7067 ) ;
@@ -128,70 +125,86 @@ function Criteria() {
128125 ) ;
129126}
130127
131- function Pitch ( ) {
128+ function PitchDrawer ( { open, onClose } ) {
129+ const [ form , setForm ] = React . useState ( PITCH_BLANK ) ;
130+ const [ sent , setSent ] = React . useState ( false ) ;
131+ React . useEffect ( ( ) => {
132+ if ( open ) setSent ( false ) ;
133+ } , [ open ] ) ;
134+ const set = ( k ) => ( e ) => setForm ( ( f ) => Object . assign ( { } , f , { [ k ] : e . target . value } ) ) ;
135+ const invalid = form . email . length > 0 && ! / ^ [ ^ @ \s ] + @ [ ^ @ \s ] + \. [ ^ @ \s ] + $ / . test ( form . email ) ;
136+ const ready = form . first && form . last && form . email && ! invalid && form . phone ;
132137 return (
133- < section className = "sect" >
134- < div className = "wrap grid2" >
135- < div className = "d-flex flex-column gap-3" >
136- < p className = "eyebrow" > START THE CONVERSATION</ p >
137- < h2 className = "h2" > Have a project and looking for a venture-style partner?</ h2 >
138- < p className = "lede" >
139- Send the product, the stage you are at and what you need built. A delivery lead and a
140- partner review it together and answer with a proposed structure.
141- </ p >
142- < div className = "d-flex gap-3 flex-wrap" >
143- < Button
144- variant = "outline-primary"
145- onClick = { ( ) => {
146- location . href = 'CodeBoxx.html#solutions' ;
147- } }
148- >
149- See the Studio
150- </ Button >
151- </ div >
138+ < Offcanvas show = { open } onHide = { onClose } placement = "end" className = "pitch-offcanvas" >
139+ < Offcanvas . Header className = "site-header" >
140+ < div className = "d-flex flex-column gap-3 align-items-start" >
141+ < span className = "kicker" > Ventures</ span >
142+ < h3 className = "ptitle" > Pitch Your Project</ h3 >
152143 </ div >
153- < div className = "panel" >
154- < h3 className = "ptitle" > Submit your project</ h3 >
155- < Form . Group >
156- < Form . Label > Full Name</ Form . Label >
157- < Form . Control id = "v-name" placeholder = "First Last" />
158- </ Form . Group >
159- < Form . Group >
160- < Form . Label > Email</ Form . Label >
161- < Form . Control id = "v-email" placeholder = "name@company.com" />
162- </ Form . Group >
163- < Form . Group >
164- < Form . Label > Company or Product</ Form . Label >
165- < Form . Control id = "v-company" placeholder = "codeboxx-enterprise-primary" />
166- </ Form . Group >
167- < Form . Group >
168- < Form . Label > Stage</ Form . Label >
169- < Form . Control id = "v-stage" placeholder = "Idea, prototype, or in market" />
170- </ Form . Group >
171- < div className = "rule" />
172- < div className = "form-actions" >
173- < span className = "form-actions-note" > Reviewed within one business day.</ span >
174- < Button size = "lg" > Send</ Button >
175- </ div >
144+ < Button size = "sm" variant = "ghost" onClick = { onClose } >
145+ Close
146+ </ Button >
147+ </ Offcanvas . Header >
148+ < Offcanvas . Body className = "d-flex flex-column gap-4" >
149+ < div className = "form-row-2" >
150+ < Form . Control placeholder = "First Name" value = { form . first } onChange = { set ( 'first' ) } />
151+ < Form . Control placeholder = "Last Name" value = { form . last } onChange = { set ( 'last' ) } />
176152 </ div >
177- </ div >
178- </ section >
153+ < Form . Group >
154+ < Form . Control
155+ placeholder = "Email"
156+ value = { form . email }
157+ isInvalid = { invalid }
158+ onChange = { set ( 'email' ) }
159+ />
160+ < Form . Control . Feedback type = "invalid" >
161+ Invalid address. Missing domain.
162+ </ Form . Control . Feedback >
163+ </ Form . Group >
164+ < Form . Control placeholder = "Phone" value = { form . phone } onChange = { set ( 'phone' ) } />
165+ < Form . Group >
166+ < Form . Label > What kind of project</ Form . Label >
167+ < Form . Select aria-label = "What kind of project" value = { form . kind } onChange = { set ( 'kind' ) } >
168+ < option value = "" > Select</ option >
169+ { PROJECT_KINDS . map ( ( k ) => (
170+ < option key = { k } value = { k } >
171+ { k }
172+ </ option >
173+ ) ) }
174+ </ Form . Select >
175+ </ Form . Group >
176+ < Form . Group >
177+ < Form . Label > Describe your project in a few words</ Form . Label >
178+ < Form . Control as = "textarea" rows = { 4 } value = { form . details } onChange = { set ( 'details' ) } />
179+ </ Form . Group >
180+ < div className = "rule" />
181+ < div className = "form-actions" >
182+ < span className = { 'form-actions-note' + ( sent ? ' sent' : '' ) } >
183+ { sent ? 'Pitch received.' : 'Reviewed within one business day.' }
184+ </ span >
185+ < Button size = "lg" disabled = { ! ready } onClick = { ( ) => setSent ( true ) } >
186+ Submit
187+ </ Button >
188+ </ div >
189+ </ Offcanvas . Body >
190+ </ Offcanvas >
179191 ) ;
180192}
181193
182194function VenturesPage ( ) {
195+ const [ pitchOpen , setPitchOpen ] = React . useState ( false ) ;
183196 return (
184197 < div id = "top" >
185198 < TopBar
186199 onCodi = { ( ) => {
187200 location . href = '/#contact' ;
188201 } }
189202 />
190- < Band />
203+ < Band onPitch = { ( ) => setPitchOpen ( true ) } />
191204 < Models />
192205 < Criteria />
193- < Pitch />
194206 < Footer />
207+ < PitchDrawer open = { pitchOpen } onClose = { ( ) => setPitchOpen ( false ) } />
195208 </ div >
196209 ) ;
197210}
0 commit comments