fixed device registration and onboarding flow

This commit is contained in:
akdeb 2025-04-23 13:24:16 +01:00
parent c4743896a4
commit 953169d8ad
9 changed files with 128 additions and 468 deletions

View file

@ -4,9 +4,8 @@ import { encodedRedirect } from "@/utils/utils";
import { createClient } from "@/utils/supabase/server";
import { headers } from "next/headers";
import { redirect } from "next/navigation";
import { getMacAddressFromDeviceCode, isValidMacAddress } from "@/lib/utils";
import { addUserToDevice, dbCheckUserCode } from "@/db/devices";
import { getSimpleUserById, updateUser } from "@/db/users";
import { getSimpleUserById } from "@/db/users";
export async function deleteUserApiKey(userId: string) {
const supabase = createClient();
@ -174,30 +173,3 @@ export const isPremiumUser = async (userId: string) => {
const dbUser = await getSimpleUserById(supabase, userId);
return dbUser?.is_premium;
};
export async function registerDevice(userId: string, deviceCode: string) {
// check if deviceCode is valid mac address
if (!isValidMacAddress(deviceCode)) {
return { error: "Invalid device code" };
}
const supabase = createClient();
const { data, error } = await supabase
.from("devices")
.insert({
user_id: userId,
user_code: deviceCode, // this is the device code that the user will use to register their device (friendly code preferred)
mac_address: deviceCode,
}).select();
if (error) {
console.log(error);
return { error: "Error registering device" };
}
if (data && data.length > 0) {
await updateUser(supabase, { device_id: data[0].device_id }, userId);
}
return { error: null };
}

View file

@ -1,135 +1,57 @@
"use client";
import { Progress } from "@/components/ui/progress";
import { ArrowLeft, ArrowRight } from "lucide-react";
import React, { useState } from "react";
import { Button } from "@/components/ui/button";
import UserType from "./UserType";
import React from "react";
import GeneralUserForm from "../Settings/UserForm";
import DoctorForm from "../Settings/DoctorForm";
import { useRouter } from "next/navigation";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { checkDoctorAction } from "@/app/actions";
import { useToast } from "@/components/ui/use-toast";
type TUserType = "doctor" | "user" | "business";
import { createClient } from "@/utils/supabase/client";
import { updateUser } from "@/db/users";
import { Loader2 } from "lucide-react";
const Steps: React.FC<{
selectedUser: IUser;
}> = ({ selectedUser }) => {
selectedUser?: IUser;
userId: string;
}> = ({ selectedUser, userId }) => {
const supabase = createClient();
const router = useRouter();
const { toast } = useToast();
const [progress, setProgress] = React.useState(40);
const [step, setStep] = React.useState(0);
const [selectedType, setSelectedType] = useState<TUserType | null>(null);
const [doctorAuthCode, setDoctorAuthCode] = useState<string>("");
const onSelectType = (type: TUserType) => {
setSelectedType(type);
setStep(1);
setProgress(progress + 30);
};
const onClickBack = () => {
setStep(step - 1);
setProgress(progress - 30);
};
const [progress, setProgress] = React.useState(50);
const [step, setStep] = React.useState(1);
const onClickFormCallback = async () => {
if (selectedType === "doctor") {
const res = await checkDoctorAction(doctorAuthCode);
if (!res) {
toast({
description:
"Your sign-up code did not match our records. Try again or reach out to us for help.",
});
return;
}
}
setStep(step + 1);
setProgress(progress + 30);
setProgress(progress + 50);
router.push("/home");
};
const CurrentForm = () => {
if (step === 0) {
return (
<UserType
selectedUser={selectedUser}
onSelectType={onSelectType}
selectedType={selectedType}
/>
);
} else {
if (selectedType === "doctor") {
return (
<DoctorForm
selectedUser={selectedUser}
heading={<Navigation />}
onClickCallback={onClickFormCallback}
/>
);
} else {
return (
<GeneralUserForm
selectedUser={selectedUser}
heading={<Navigation />}
onClickCallback={onClickFormCallback}
/>
);
}
}
};
const Navigation = () => {
if (step === 1) {
return (
<div className="flex flex-col gap-4">
<div className="mt-4 text-center flex flex-row items-center justify-between gap-4">
{step > 0 && (
<Button
onClick={onClickBack}
variant="link"
size="sm"
type="button"
className="mr-4 pl-0 flex flex-row items-center gap-2"
>
<ArrowLeft size={16} /> Back
</Button>
)}
{step > 0 && (
<Button
disabled={!selectedType}
className="flex flex-row items-center gap-2"
size="sm"
type="submit"
>
Continue <ArrowRight size={16} />
</Button>
)}
</div>
{selectedType === "doctor" && (
<div className="flex flex-col gap-2">
<Label className="flex flex-row gap-4 items-center">
{"Your unique sign-up code"}
</Label>
<Input
type="text"
autoFocus
required
value={doctorAuthCode}
onChange={(e) => setDoctorAuthCode(e.target.value)}
placeholder="Sign-up code"
className="max-w-screen-sm h-10 bg-white"
autoComplete="on"
style={{
fontSize: 16,
}}
/>
</div>
)}
</div>
<GeneralUserForm
selectedUser={selectedUser}
userId={userId}
onClickCallback={onClickFormCallback}
onSave={
async (values, userType) => {
await updateUser(
supabase,
{
supervisee_age: values.supervisee_age,
supervisee_name: values.supervisee_name,
supervisee_persona: values.supervisee_persona,
user_info: {
user_type: userType,
user_metadata: values,
},
},
userId);
}}
disabled={false}
/>
);
} else {
return <Loader2 className="w-4 h-4 animate-spin" />;
}
};
let heading = "Let's get your Elato device & account set up";
@ -137,11 +59,7 @@ const Steps: React.FC<{
"We want to make sure that your Elato is set up to provide you the best experience possible.";
if (step === 1) {
if (selectedType === "doctor") {
heading = "Hello Doctor!";
subHeading =
"With the following details we will be able to personalize your and your patients' Elato experience.";
} else {
{
heading = "Hello there!";
subHeading =
"With the following details we will be able to personalize your Elato experience.";
@ -158,4 +76,4 @@ const Steps: React.FC<{
);
};
export default Steps;
export default Steps;

View file

@ -24,12 +24,6 @@ const UserTypes: IUserType[] = [
title: "You are looking to use Elato for personal use",
icon: <User />,
},
{
type: "doctor",
name: "Doctor",
title: "You are a licensed doctor or physician",
icon: <Hospital />,
},
{
type: "business",
name: "Business",
@ -40,10 +34,9 @@ const UserTypes: IUserType[] = [
];
const UserType: React.FC<{
selectedUser: IUser;
selectedType: TUserType | null;
onSelectType: (type: TUserType) => void;
}> = ({ selectedType, onSelectType, selectedUser }) => {
}> = ({ selectedType, onSelectType }) => {
const onPickType = async (userType: IUserType) => {
if (!userType.disabled) {
onSelectType(userType.type);
@ -55,7 +48,7 @@ const UserType: React.FC<{
<h1 className="text-xl font-medium my-4 inline">
You are a <ArrowRight className="inline-block" />{" "}
</h1>
<div className="grid grid-cols-1 md:grid-cols-3 mt-2 gap-6">
<div className="grid grid-cols-1 md:grid-cols-2 mt-2 gap-6">
{UserTypes.map((userType) => (
<Card
key={userType.type}
@ -98,6 +91,4 @@ const UserType: React.FC<{
</div>
</div>
);
};
export default UserType;
};

View file

@ -1,9 +1,10 @@
import { registerDevice, signOutAction } from "@/app/actions";
import { connectUserToDevice, signOutAction } from "@/app/actions";
import { Button } from "@/components/ui/button";
import { Label } from "@/components/ui/label";
import { Input } from "@/components/ui/input";
import { LogOut } from "lucide-react";
import DoctorForm from "./DoctorForm";
import GeneralUserForm from "./UserForm";
import { Slider } from "@/components/ui/slider";
import { updateUser } from "@/db/users";
@ -12,12 +13,6 @@ import { createClient } from "@/utils/supabase/client";
import React, { useCallback } from "react";
import { doesUserHaveADevice, updateDevice } from "@/db/devices";
import { useToast } from "@/components/ui/use-toast";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
TooltipProvider,
} from "@/components/ui/tooltip";
interface AppSettingsProps {
selectedUser: IUser;
@ -35,7 +30,7 @@ const AppSettings: React.FC<AppSettingsProps> = ({
const userFormRef = React.useRef<{ submitForm: () => void } | null>(null);
const [deviceCode, setDeviceCode] = React.useState("");
const [error, setError] = React.useState("");
const handleSave = () => {
if (selectedUser.user_info.user_type === "doctor") {
doctorFormRef.current?.submitForm();
@ -50,6 +45,11 @@ const AppSettings: React.FC<AppSettingsProps> = ({
);
}, [selectedUser.user_id, supabase]);
React.useEffect(() => {
checkIfUserHasDevice();
}, [checkIfUserHasDevice]);
const [volume, setVolume] = React.useState([
selectedUser.device?.volume ?? 50,
]);
@ -69,7 +69,8 @@ const AppSettings: React.FC<AppSettingsProps> = ({
debouncedUpdateVolume();
};
const onSave = async (values: any, userType: "doctor" | "user") => {
const onSave = async (values: any, userType: "doctor" | "user", userId: string) => {
await updateUser(
supabase,
{
@ -81,29 +82,22 @@ const AppSettings: React.FC<AppSettingsProps> = ({
user_metadata: values,
},
},
selectedUser!.user_id);
toast({
description: "Your prefereces have been saved!",
});
}
userId);
toast({
description: "Your prefereces have been saved!",
});
}
return (
<>
{selectedUser.user_info.user_type === "doctor" ? (
<DoctorForm
<GeneralUserForm
selectedUser={selectedUser}
userId={selectedUser.user_id}
heading={heading}
onSave={onSave}
onClickCallback={() => handleSave()}
/>
) : (
<GeneralUserForm
selectedUser={selectedUser}
heading={heading}
onSave={onSave}
onClickCallback={() => handleSave()}
/>
)}
<section className="space-y-4 max-w-screen-sm mt-12">
<h2 className="text-lg font-semibold border-b border-gray-200 pb-2">
Device settings
@ -112,18 +106,8 @@ const AppSettings: React.FC<AppSettingsProps> = ({
<div className="flex flex-col gap-2">
<div className="flex flex-row items-center gap-2">
<Label className="text-sm font-medium text-gray-700">
Register your device
</Label>
<TooltipProvider>
<Tooltip>
<TooltipTrigger className="inline-flex items-center justify-center h-4 w-4 rounded-full bg-gray-200 text-gray-600 text-xs hover:bg-gray-300">
?
</TooltipTrigger>
<TooltipContent>
<p>For simplicity, you can register your ESP32 MAC address here. <br /> Ideally you want this to be a friendly code for your device.</p>
</TooltipContent>
</Tooltip>
</TooltipProvider>
Register your device
</Label>
<div
className={`rounded-full flex-shrink-0 h-2 w-2 ${
isConnected ? 'bg-green-500' : 'bg-amber-500'
@ -131,22 +115,23 @@ const AppSettings: React.FC<AppSettingsProps> = ({
/>
</div>
<div className="flex flex-row items-center gap-2 mt-2">
<Input
value={deviceCode}
disabled={isConnected}
onChange={(e) => setDeviceCode(e.target.value)}
placeholder={isConnected ? "**********" : "Enter your ESP32-S3 MAC address"}
placeholder={isConnected ? "**********" : "Enter your device code"}
maxLength={100}
/>
<Button
size="sm"
variant="outline"
disabled={isConnected}
onClick={async () => {
const result = await registerDevice(selectedUser.user_id, deviceCode);
if (result.error) {
setError(result.error);
const result = await connectUserToDevice(selectedUser.user_id, deviceCode);
if (!result) {
setError("Error registering device");
}
checkIfUserHasDevice();
}}
@ -157,10 +142,10 @@ const AppSettings: React.FC<AppSettingsProps> = ({
<p className="text-xs text-gray-400">
{isConnected ? <span className="font-medium text-gray-800">Registered!</span> :
error ? <span className="text-red-500">{error}.</span> :
"Add your ESP32-S3 MAC address (e.g. 12:34:56:78:9A:BC) to your account to register it."
"Enter your device code to register it."
}
</p>
</div>
</div>
<div className="flex flex-col gap-2 mt-2">
<Label className="text-sm font-medium text-gray-700">
Logged in as
@ -212,4 +197,4 @@ const AppSettings: React.FC<AppSettingsProps> = ({
);
};
export default AppSettings;
export default AppSettings;

View file

@ -1,218 +0,0 @@
import {
Form,
FormControl,
FormField,
FormItem,
FormLabel,
FormMessage,
} from "@/components/ui/form";
import { useForm } from "react-hook-form";
import * as z from "zod";
import { Input } from "@/components/ui/input";
import { Textarea } from "@/components/ui/textarea";
import React, { forwardRef } from "react";
import { Button } from "@/components/ui/button";
interface DoctorFormProps {
selectedUser: IUser;
heading: React.ReactNode;
onSave?: (values: any, userType: "doctor" | "user") => void;
onClickCallback: () => void;
}
export const doctorSettingsSchema = z.object({
doctor_name: z.string().min(1).max(50),
specialization: z.string().min(1).max(500),
hospital_name: z.string().min(1).max(200),
favorite_phrases: z.string().min(1).max(200),
hospital_layout: z.string().min(1).max(500),
});
export type DoctorSettingsInput = z.infer<typeof doctorSettingsSchema>;
const DoctorForm = ({ selectedUser, heading, onSave, onClickCallback }: DoctorFormProps) => {
const userMetadata = selectedUser.user_info
.user_metadata as IDoctorMetadata;
const form = useForm<DoctorSettingsInput>({
defaultValues: {
doctor_name:
userMetadata?.doctor_name ?? selectedUser.supervisee_name,
specialization: userMetadata?.specialization ?? "",
hospital_name: userMetadata?.hospital_name ?? "",
favorite_phrases: userMetadata?.favorite_phrases ?? "",
hospital_layout: userMetadata?.hospital_layout ?? "",
},
});
async function onSubmit(values: z.infer<typeof doctorSettingsSchema>) {
onSave && onSave(values, "doctor");
}
const handleSave = () => {
onSave && onSave(form.getValues(), "doctor");
onClickCallback();
};
return (
<Form {...form}>
<form
onSubmit={form.handleSubmit(onSubmit)}
className="flex flex-col gap-8 mb-4 max-w-screen-sm"
>
{heading}
<section className="space-y-4">
<h2 className="text-lg font-semibold border-b border-gray-200 pb-2">
Basic Info
</h2>
<FormField
control={form.control}
name="doctor_name"
render={({ field }) => (
<FormItem className="w-full rounded-md">
<FormLabel className="text-sm font-medium text-gray-700">
{"Your Name"}
</FormLabel>
<FormControl>
<Input
// autoFocus
required
placeholder="e.g. Dr. John Doe"
{...field}
className="mt-1"
// autoComplete="on"
// style={{
// fontSize: 16,
// }}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</section>
<section className="space-y-4 flex flex-col gap-2">
<h2 className="text-lg font-semibold border-b border-gray-200 pb-2">
Hospital Details
</h2>
<FormField
control={form.control}
name="hospital_name"
render={({ field }) => (
<FormItem className="w-full rounded-md">
<FormLabel className="text-sm font-medium text-gray-700">
{"Hospital or clinic name(s)"}
</FormLabel>
<FormControl>
<Input
// autoFocus
required
placeholder="e.g. St. Mary's Hospital"
{...field}
// className="max-w-screen-sm h-10 bg-white"
// autoComplete="on"
// style={{
// fontSize: 16,
// }}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="favorite_phrases"
render={({ field }) => (
<FormItem className="w-full rounded-md">
<FormLabel className="text-sm font-medium text-gray-700">
{"Nurse's favorite phrases"}
</FormLabel>
<FormControl>
<Textarea
rows={3}
placeholder={
"e.g. 'You're doing great!' or 'Take a deep breath'"
}
{...field}
// className="max-w-screen-sm bg-white"
// autoComplete="on"
// style={{
// fontSize: 16,
// }}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="specialization"
render={({ field }) => (
<FormItem className="w-full rounded-md">
<FormLabel className="text-sm font-medium text-gray-700">
{"Specializations and conditions treated"}
</FormLabel>
<FormControl>
<Textarea
rows={5}
placeholder={
"e.g. Pediatrician neurologist or Cardiologist treating heart conditions"
}
{...field}
// className="max-w-screen-sm bg-white"
// autoComplete="on"
// style={{
// fontSize: 16,
// }}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="hospital_layout"
render={({ field }) => (
<FormItem className="w-full rounded-md">
<FormLabel className="text-sm font-medium text-gray-700">
{"Hospital layout"}
</FormLabel>
<FormControl>
<Textarea
rows={5}
placeholder={
"e.g. Our hospital has 2 floors. Main entrance leads to the lobby with reception desk straight ahead. \n\nFloor 1: Outpatient clinics and cafeteria. \nFloor 2: Surgery and recovery rooms. \n\nCafeteria is on the ground floor."
}
{...field}
// className="max-w-screen-sm bg-white"
// autoComplete="on"
// style={{
// fontSize: 16,
// }}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</section>
<Button
variant="default"
className="rounded-full w-fit mt-4"
size="sm"
onClick={handleSave}
type="submit"
>
Save settings
</Button>
</form>
</Form>
);
};
DoctorForm.displayName = "DoctorForm";
export default DoctorForm;

View file

@ -19,14 +19,17 @@ import {
userFormPersonaPlaceholder,
} from "@/lib/data";
import { Button } from "@/components/ui/button";
import { Loader2 } from "lucide-react";
interface GeneralUserFormProps {
selectedUser: IUser;
heading: React.ReactNode;
onSave?: (values: any, userType: "doctor" | "user") => void;
selectedUser?: IUser;
heading?: React.ReactNode;
onSave?: (values: any, userType: "doctor" | "user", userId: string) => void;
onClickCallback: () => void;
userId: string;
disabled?: boolean;
}
export const UserSettingsSchema = z.object({
supervisee_name: z.string().min(1).max(50),
supervisee_age: z.number().min(1).max(18),
@ -40,7 +43,7 @@ export const UserSettingsSchema = z.object({
export type GeneralUserInput = z.infer<typeof UserSettingsSchema>;
const GeneralUserForm = ({ selectedUser, heading, onSave, onClickCallback }: GeneralUserFormProps) => {
const GeneralUserForm = ({ selectedUser, onSave, onClickCallback, userId, heading, disabled }: GeneralUserFormProps) => {
const form = useForm<GeneralUserInput>({
defaultValues: {
supervisee_name: selectedUser?.supervisee_name ?? "",
@ -50,11 +53,11 @@ const GeneralUserForm = ({ selectedUser, heading, onSave, onClickCallback }: Gen
});
async function onSubmit(values: z.infer<typeof UserSettingsSchema>) {
onSave && onSave(values, "user");
onSave && onSave(values, "user", userId);
}
const handleSave = () => {
onSave && onSave(form.getValues(), "user");
onSave && onSave(form.getValues(), "user", userId);
onClickCallback();
};
@ -113,11 +116,11 @@ const GeneralUserForm = ({ selectedUser, heading, onSave, onClickCallback }: Gen
required
placeholder="e.g. 8"
{...field}
// className="max-w-screen-sm h-10 bg-white"
// autoComplete="on"
// style={{
// fontSize: 16,
// }}
/>
</FormControl>
<FormMessage />
@ -139,11 +142,11 @@ const GeneralUserForm = ({ selectedUser, heading, onSave, onClickCallback }: Gen
userFormPersonaPlaceholder
}
{...field}
// className="max-w-screen-sm bg-white"
// autoComplete="on"
// style={{
// fontSize: 16,
// }}
/>
</FormControl>
<FormMessage />
@ -154,16 +157,17 @@ const GeneralUserForm = ({ selectedUser, heading, onSave, onClickCallback }: Gen
</section>
<Button
variant="default"
className="rounded-full w-fit mt-4"
className="rounded-full w-fit mt-4 flex flex-row items-center gap-2"
size="sm"
onClick={handleSave}
type="submit"
disabled={disabled}
>
Save settings
{disabled ? <Loader2 className="w-4 h-4 animate-spin" /> : <span>Save settings</span>}
</Button>
</form>
</Form>
);
};
export default GeneralUserForm;
export default GeneralUserForm;

View file

@ -1,5 +1,4 @@
import { createClient } from "@/utils/supabase/server";
import { getUserById } from "@/db/users";
import Steps from "../components/Onboarding/Steps";
export default async function Home() {
@ -9,11 +8,9 @@ export default async function Home() {
data: { user },
} = await supabase.auth.getUser();
const dbUser = user ? await getUserById(supabase, user.id) : undefined;
return (
<div className="flex flex-col gap-2">
{dbUser && <Steps selectedUser={dbUser} />}
<Steps userId={user?.id ?? ""} />
</div>
);
}
}

View file

@ -1,8 +1,9 @@
import { SupabaseClient } from "@supabase/supabase-js";
import { updateUser } from "./users";
export const dbCheckUserCode = async (
supabase: SupabaseClient,
userCode: string
userCode: string,
) => {
const { data, error } = await supabase
.from("devices")
@ -19,9 +20,12 @@ export const dbCheckUserCode = async (
export const updateDevice = async (
supabase: SupabaseClient,
device: Partial<IDevice>,
device_id: string
device_id: string,
) => {
const { error } = await supabase.from("devices").update(device).eq("device_id", device_id);
const { error } = await supabase.from("devices").update(device).eq(
"device_id",
device_id,
);
if (error) {
throw error;
}
@ -30,23 +34,29 @@ export const updateDevice = async (
export const addUserToDevice = async (
supabase: SupabaseClient,
userCode: string,
userId: string
userId: string,
) => {
const { error } = await supabase
const { data, error } = await supabase
.from("devices")
.update({ user_id: userId })
.eq("user_code", userCode);
.eq("user_code", userCode)
.select("*")
.maybeSingle();
if (error) {
return false;
}
if (data) {
await updateUser(supabase, { device_id: data.device_id }, userId);
}
return true;
};
export const doesUserHaveADevice = async (
supabase: SupabaseClient,
userId: string
userId: string,
) => {
const { data, error } = await supabase
.from("devices")

View file

@ -3,7 +3,7 @@ import { type SupabaseClient, type User } from "@supabase/supabase-js";
export const createUser = async (
supabase: SupabaseClient,
user: User,
userProps: Partial<IUser>
userProps: Partial<IUser>,
) => {
// console.log("creating user", user, userProps);
@ -18,9 +18,10 @@ export const createUser = async (
supervisee_persona: "",
personality_id: userProps.personality_id, // selecting default personality
session_time: 0,
avatar_url:
user.user_metadata?.avatar_url ??
`/user_avatar/user_avatar_${Math.floor(Math.random() * 10)}.png`,
avatar_url: user.user_metadata?.avatar_url ??
`/user_avatar/user_avatar_${
Math.floor(Math.random() * 10)
}.png`,
} as IUser,
]);
@ -31,7 +32,7 @@ export const createUser = async (
export const getSimpleUserById = async (
supabase: SupabaseClient,
id: string
id: string,
) => {
const { data, error } = await supabase
.from("users")
@ -40,7 +41,7 @@ export const getSimpleUserById = async (
.single();
if (error) {
console.log("error", error);
console.log("error in getSimpleUserById", error);
}
return data as IUser | undefined;
@ -50,13 +51,13 @@ export const getUserById = async (supabase: SupabaseClient, id: string) => {
const { data, error } = await supabase
.from("users")
.select(
`*, personality:personality_id(*), device:devices!users_device_id_fkey(device_id, volume)`
`*, personality:personality_id(*), device:devices!users_device_id_fkey(device_id, volume)`,
)
.eq("user_id", id)
.single();
if (error) {
console.log("error", error);
console.log("error in getUserById", error);
}
return data as IUser | undefined;
@ -64,7 +65,7 @@ export const getUserById = async (supabase: SupabaseClient, id: string) => {
export const doesUserExist = async (
supabase: SupabaseClient,
authUser: User
authUser: User,
) => {
const { data: user, error } = await supabase
.from("users")
@ -73,7 +74,7 @@ export const doesUserExist = async (
.single();
if (error) {
console.log("error", error);
console.log("error in doesUserExist", error);
}
return !!user;
@ -82,7 +83,7 @@ export const doesUserExist = async (
export const updateUser = async (
supabase: SupabaseClient,
user: Partial<IUser>,
userId: string
userId: string,
) => {
const { error } = await supabase
.from("users")