Skip to content
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

Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions api/supabase/queries/profiles.ts
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];
}
179 changes: 179 additions & 0 deletions app/onboarding/page.tsx
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}`;
Copy link
Collaborator

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';

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>
Copy link
Collaborator

Choose a reason for hiding this comment

The 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);
Copy link
Collaborator

Choose a reason for hiding this comment

The 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;
33 changes: 33 additions & 0 deletions app/onboarding/styles.ts
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;
`;
31 changes: 31 additions & 0 deletions hooks/useProfile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { useState } from 'react';
Copy link
Collaborator

Choose a reason for hiding this comment

The 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,
};
};
9 changes: 9 additions & 0 deletions styles/colors.ts
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;
9 changes: 9 additions & 0 deletions types/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,15 @@ import type { UUID } from 'crypto';

export type Season = 'SPRING' | 'SUMMER' | 'FALL' | 'WINTER';

export interface Profile {
user_id: UUID;
state: string;
email: string;
phone_num: string;
user_type: string;
has_plot: boolean;
}

export interface Plant {
id: UUID;
plant_name: string;
Expand Down