-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[feat] Uperting profiles to Supabase for onboarding #12
Changes from 4 commits
82dc058
2b7378b
bb446e6
adf0c22
9e892c6
e3bbaa5
0748c1b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { Profile } from '@/types/schema'; | ||
import supabase from '../createClient'; | ||
|
||
export async function upsertProfile(profile: Profile) { | ||
const { data, error } = await supabase | ||
.from('profiles') | ||
.upsert(profile) | ||
.select(); | ||
|
||
if (error) throw new Error(`Error upserting profile data: ${error.message}`); | ||
|
||
return data[0]; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
'use client'; | ||
|
||
import React, { useState } from 'react'; | ||
import { upsertProfile } from '@/api/supabase/queries/profiles'; | ||
import { Profile } from '@/types/schema'; | ||
|
||
type UUID = `${string}-${string}-${string}-${string}-${string}`; | ||
const generateUUID = (): UUID => { | ||
return crypto.randomUUID() as UUID; | ||
}; | ||
const id = generateUUID(); | ||
kevin3656 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
// Define the possible options for each question | ||
const states = ['Tennessee', 'Missouri']; | ||
const gardenTypes = ['Individual', 'Community', 'School']; | ||
const plotOptions = [ | ||
{ label: 'yes', value: true }, | ||
{ label: 'no', value: false }, | ||
]; | ||
//Interfaces and props to avoid typ errors on Lint | ||
interface StateSelectionProps { | ||
selectedState: string; | ||
setSelectedState: React.Dispatch<React.SetStateAction<string>>; | ||
} | ||
|
||
interface GardenTypeSelectionProps { | ||
selectedGardenType: string; | ||
setSelectedGardenType: React.Dispatch<React.SetStateAction<string>>; | ||
} | ||
|
||
interface PlotSelectionProps { | ||
selectedPlot: boolean | null; | ||
setSelectedPlot: React.Dispatch<React.SetStateAction<boolean>>; | ||
} | ||
|
||
// Select State | ||
const StateSelection: React.FC<StateSelectionProps> = ({ | ||
selectedState, | ||
setSelectedState, | ||
}) => { | ||
return ( | ||
<div> | ||
<h2>Which state do you live in?</h2> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this will probably be a radio button as well eventually, but this is all right for now! |
||
<select | ||
value={selectedState} | ||
onChange={e => setSelectedState(e.target.value)} | ||
> | ||
<option value="" disabled> | ||
Select a state | ||
</option> | ||
{states.map(state => ( | ||
<option key={state} value={state}> | ||
{state} | ||
</option> | ||
))} | ||
</select> | ||
</div> | ||
); | ||
}; | ||
|
||
// Step 2: Select garden type | ||
|
||
const GardenTypeSelection: React.FC<GardenTypeSelectionProps> = ({ | ||
selectedGardenType, | ||
setSelectedGardenType, | ||
}) => { | ||
return ( | ||
<div> | ||
<h2>What type of garden do you want to create?</h2> | ||
{gardenTypes.map(type => ( | ||
<label key={type}> | ||
<input | ||
type="radio" | ||
name="gardenType" | ||
value={type} | ||
checked={selectedGardenType === type} | ||
onChange={e => setSelectedGardenType(e.target.value)} | ||
/> | ||
{type} | ||
</label> | ||
))} | ||
</div> | ||
); | ||
}; | ||
|
||
// Step 3: Do you have a plot? | ||
const PlotSelection: React.FC<PlotSelectionProps> = ({ | ||
selectedPlot, | ||
setSelectedPlot, | ||
}) => { | ||
return ( | ||
<div> | ||
<h2>Do you already have a plot?</h2> | ||
{plotOptions.map(option => ( | ||
<label key={option.label}> | ||
<input | ||
type="radio" | ||
name="plot" | ||
value={String(option.value)} | ||
checked={selectedPlot === option.value} | ||
onChange={() => setSelectedPlot(option.value)} | ||
/> | ||
{option.label} | ||
</label> | ||
))} | ||
</div> | ||
); | ||
}; | ||
|
||
// Main Onboarding Component | ||
const OnboardingFlow = () => { | ||
const [step, setStep] = useState(1); | ||
const [selectedState, setSelectedState] = useState<string>(''); | ||
const [selectedGardenType, setSelectedGardenType] = useState<string>(''); | ||
const [selectedPlot, setSelectedPlot] = useState<boolean>(false); | ||
|
||
const handleNext = () => { | ||
setStep(step + 1); | ||
}; | ||
|
||
const handleBack = () => { | ||
setStep(step - 1); | ||
}; | ||
|
||
const handleSubmit = async () => { | ||
const profile: Profile = { | ||
user_id: id, | ||
state: selectedState, | ||
email: '', | ||
kevin3656 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
phone_num: '', | ||
user_type: selectedGardenType, | ||
has_plot: selectedPlot, | ||
}; | ||
try { | ||
const updatedProfile = await upsertProfile(profile); | ||
console.log('Profile successfully upserted:', updatedProfile); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. same thing about removing the console log eventually. let's remove this line |
||
} catch (err) { | ||
console.error('Error upserting profile:', err); | ||
kevin3656 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} finally { | ||
} | ||
console.log('Submitted data: ', profile); | ||
ccatherinetan marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// Handle form submission, e.g., send to a server or display a confirmation | ||
}; | ||
|
||
return ( | ||
<div> | ||
{step === 1 && ( | ||
<StateSelection | ||
selectedState={selectedState} | ||
setSelectedState={setSelectedState} | ||
/> | ||
)} | ||
{step === 2 && ( | ||
<GardenTypeSelection | ||
selectedGardenType={selectedGardenType} | ||
setSelectedGardenType={setSelectedGardenType} | ||
/> | ||
)} | ||
{step === 3 && ( | ||
<PlotSelection | ||
selectedPlot={selectedPlot} | ||
setSelectedPlot={setSelectedPlot} | ||
/> | ||
)} | ||
|
||
<div> | ||
{step > 1 && <button onClick={handleBack}>Back</button>} | ||
{step < 3 && ( | ||
<button onClick={handleNext} disabled={!selectedState && step === 1}> | ||
Next | ||
</button> | ||
)} | ||
{step === 3 && <button onClick={handleSubmit}>Submit</button>} | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default OnboardingFlow; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import styled from 'styled-components'; | ||
import COLORS from '@/styles/colors'; | ||
|
||
export const PageContainer = styled.div` | ||
width: 100%; | ||
height: 100svh; | ||
background-color: ${COLORS.seed}; | ||
`; | ||
export const ContentContainer = styled.div` | ||
display: flex; /* Enable flexbox */ | ||
flex-direction: column; | ||
align-items: center; | ||
justify-content: center; | ||
|
||
height: 100vh; | ||
`; | ||
|
||
export const ButtonContainer = styled.div` | ||
display: flex; /* Enable flexbox */ | ||
flex-direction: row; | ||
align-items: center; | ||
justify-content: center; | ||
gap: 10px; | ||
`; | ||
|
||
export const Button = styled.button` | ||
width: 9.375rem; | ||
height: 3.125rem; | ||
border-radius: 25rem; | ||
border-width: 0px; | ||
background-color: ${COLORS.sprout}; | ||
color: white; | ||
`; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
import { useState } from 'react'; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's remove this file, and it'll be ready to merge! |
||
import { Profile } from '../types/schema'; | ||
|
||
const initialProfiles: Profile[] = []; | ||
|
||
export const useProfile = () => { | ||
const [profiles, setProfiles] = useState<Profile[]>(initialProfiles); | ||
|
||
const addProfile = (newProfile: Profile) => { | ||
setProfiles(prev => [...prev, newProfile]); | ||
}; | ||
|
||
const updateProfile = (index: number, updates: Partial<Profile>) => { | ||
setProfiles(prev => | ||
prev.map((profile, i) => | ||
i === index ? { ...profile, ...updates } : profile, | ||
), | ||
); | ||
}; | ||
|
||
const removeProfile = (index: number) => { | ||
setProfiles(prev => prev.filter((_, i) => i !== index)); | ||
}; | ||
|
||
return { | ||
profiles, | ||
addProfile, | ||
updateProfile, | ||
removeProfile, | ||
}; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const COLORS = { | ||
// background white | ||
seed: '#FFFBF2', | ||
|
||
//greens | ||
shrub: '#1F5A2A', | ||
sprout: '#94B506', | ||
}; | ||
export default COLORS; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we can import the UUID type!
import type { UUID } from 'crypto';