mirror of
https://github.com/supabase/supabase.git
synced 2026-10-18 15:49:09 +03:00
* duplicate page * whale init * table background * prepare * sync undocumented remote schema from master * revert remote schema sync * add lw12 tickets migration file * ticket init * set up lw12 ticket layout * finish ticket layout and customization form * lw12 ticket og * ticket styling * code highlight border * launch week migrations * local dev progress * keep local gh config * comment section * comment section * comment out username.tsx * remove lw/ticekts temp * update copy * fix migration view * redirect to try * use misc * lw12 og * share * share correct * env var * username page * update example env * push new db schema * trigger deploy * update ticket og * ticket themes * bypass browser * change env var name * fix * fix * process env * create client server side * lw announcements * promoToast * animated bg * update ticket og bg * minor details * secret ticket * social share text * social share textgst * flow text * update og * update og handler * Update index.ts * use functions.invoke and use generic supabase URL * Update index.ts * Update handler.tsx * Update package-lock.json * Update handler.tsx * add next api route * moved to vercel edge function * set revalidate * Update route.tsx * Delete lw-ticket-og.tsx * Update route.tsx * Update [username].tsx * Update [username].tsx * add more fetches * Update turbo.json * ticket themes updated * copy and layout updated * Update index.tsx * Update Ticket.tsx * Update TicketingFlow.tsx * update countdown * updated bg * small updates * moat * Update [username].tsx * Update 20240723155310_add_lw12_ticketing_schema.sql * optimistic ticket stuff og generation * Update index.tsx * updated layout * update themes in og * Update constants.ts * attr renamed * Update TicketingFlow.tsx * Update TicketActions.tsx * grammar * moar updates * Update TicketActions.tsx * Update TicketActions2.tsx * Update TicketActions.tsx * Update Hero.tsx * Update TicketingFlow.tsx * remove console logs --------- Co-authored-by: Francesco Sansalvadore <f.sansalvadore@gmail.com>
176 lines
5.3 KiB
TypeScript
176 lines
5.3 KiB
TypeScript
import React, { useEffect, useState } from 'react'
|
|
import { Button, Input, cn } from 'ui'
|
|
import { Check } from 'lucide-react'
|
|
import useConfData from '~/components/LaunchWeek/hooks/use-conf-data'
|
|
import { useBreakpoint, useDebounce } from 'common'
|
|
import { useKey } from 'react-use'
|
|
|
|
const TicketCustomizationForm = ({ className }: { className?: string }) => {
|
|
const isMobile = useBreakpoint()
|
|
const {
|
|
supabase,
|
|
userData: user,
|
|
showCustomizationForm,
|
|
setShowCustomizationForm,
|
|
} = useConfData()
|
|
const defaultFormValues = {
|
|
role: user.role,
|
|
company: user.company,
|
|
location: user.location,
|
|
}
|
|
const [formData, setFormData] = useState(defaultFormValues)
|
|
const [formState, setFormState] = useState<'idle' | 'saved' | 'saving' | 'error'>('idle')
|
|
const IS_SAVING = formState === 'saving'
|
|
const IS_SAVED = formState === 'saved'
|
|
const HAS_ERROR = formState === 'error'
|
|
|
|
useKey('Escape', () => setShowCustomizationForm && setShowCustomizationForm(false))
|
|
|
|
const handleInputChange = (name: string, value: string | boolean) => {
|
|
setFormData((prev) => ({ ...prev, [name]: value }))
|
|
}
|
|
|
|
const handleFormSubmit = async () => {
|
|
setFormState('saving')
|
|
const payload = formData
|
|
|
|
if (supabase) {
|
|
await supabase
|
|
.from('tickets')
|
|
.update(payload)
|
|
.eq('launch_week', 'lw12')
|
|
.eq('username', user.username)
|
|
.then((res) => {
|
|
if (res.error) return setFormState('error')
|
|
setFormState('saved')
|
|
setTimeout(() => {
|
|
setFormState('idle')
|
|
}, 1200)
|
|
})
|
|
}
|
|
}
|
|
|
|
const debouncedChangeHandler = useDebounce(handleFormSubmit, 1200)
|
|
|
|
useEffect(() => {
|
|
return () => setShowCustomizationForm && setShowCustomizationForm(false)
|
|
}, [])
|
|
|
|
return (
|
|
<form
|
|
className={cn(
|
|
'w-full rounded-xl bg-alternative border p-4 flex flex-col gap-2 mx-auto transition-all opacity-0 translate-y-full text-foreground-light',
|
|
showCustomizationForm && 'opacity-100 translate-y-0 duration-300',
|
|
isMobile && 'mt-2',
|
|
className
|
|
)}
|
|
onChange={(e) => {
|
|
e.preventDefault()
|
|
debouncedChangeHandler()
|
|
}}
|
|
onSubmit={(e) => {
|
|
e.preventDefault()
|
|
handleFormSubmit()
|
|
}}
|
|
>
|
|
<Input
|
|
size="small"
|
|
type="text"
|
|
placeholder="role (optional)"
|
|
value={formData.role}
|
|
onChange={(event) => {
|
|
handleInputChange('role', event.target.value)
|
|
}}
|
|
onFocus={() =>
|
|
!showCustomizationForm && setShowCustomizationForm && setShowCustomizationForm(true)
|
|
}
|
|
inputClassName={cn(IS_SAVING && 'text-foreground-lighter')}
|
|
maxLength={25}
|
|
icon={
|
|
<Check
|
|
strokeWidth={2}
|
|
className={cn(
|
|
'w-3',
|
|
!!formData.role ? 'text-brand' : 'text-foreground-lighter',
|
|
IS_SAVING && 'text-background-surface-300'
|
|
)}
|
|
/>
|
|
}
|
|
/>
|
|
<Input
|
|
size="small"
|
|
type="text"
|
|
placeholder="company (optional)"
|
|
value={formData.company}
|
|
maxLength={25}
|
|
onChange={(event) => {
|
|
handleInputChange('company', event.target.value)
|
|
}}
|
|
onFocus={() =>
|
|
!showCustomizationForm && setShowCustomizationForm && setShowCustomizationForm(true)
|
|
}
|
|
inputClassName={cn(IS_SAVING && 'text-foreground-lighter')}
|
|
icon={
|
|
<Check
|
|
strokeWidth={2}
|
|
className={cn(
|
|
'w-3',
|
|
!!formData.company ? 'text-brand' : 'text-foreground-lighter',
|
|
IS_SAVING && 'text-background-surface-300'
|
|
)}
|
|
/>
|
|
}
|
|
/>
|
|
<Input
|
|
size="small"
|
|
type="text"
|
|
placeholder="location (optional)"
|
|
value={formData.location}
|
|
maxLength={25}
|
|
onChange={(event) => {
|
|
handleInputChange('location', event.target.value)
|
|
}}
|
|
onFocus={() =>
|
|
!showCustomizationForm && setShowCustomizationForm && setShowCustomizationForm(true)
|
|
}
|
|
inputClassName={cn(IS_SAVING && 'text-foreground-lighter')}
|
|
icon={
|
|
<Check
|
|
strokeWidth={2}
|
|
className={cn(
|
|
'w-3',
|
|
!!formData.location ? 'text-brand' : 'text-foreground-lighter',
|
|
IS_SAVING && 'text-background-surface-300'
|
|
)}
|
|
/>
|
|
}
|
|
/>
|
|
<div className="flex flex-col lg:flex-row items-center justify-center md:justify-between gap-2 mt-2">
|
|
<div className="inline opacity-0 animate-fade-in text-xs text-foreground-light">
|
|
{IS_SAVED && (
|
|
<span className="inline opacity-0 animate-fade-in text-xs text-foreground-light">
|
|
Saved
|
|
</span>
|
|
)}
|
|
{HAS_ERROR && (
|
|
<span className="inline opacity-0 animate-fade-in text-xs text-foreground-light">
|
|
Something went wrong
|
|
</span>
|
|
)}
|
|
</div>
|
|
<Button
|
|
type="outline"
|
|
size="tiny"
|
|
htmlType="submit"
|
|
block={isMobile}
|
|
onClick={() => setShowCustomizationForm && setShowCustomizationForm(false)}
|
|
>
|
|
Done
|
|
</Button>
|
|
</div>
|
|
</form>
|
|
)
|
|
}
|
|
|
|
export default TicketCustomizationForm
|