From f14a7a7d802ad59294d4f03be3bb5eced6787953 Mon Sep 17 00:00:00 2001 From: "Mike P. Sinn" Date: Mon, 29 Apr 2024 20:07:14 -0600 Subject: [PATCH 1/4] Add global variable validation and update user ID retrieval Added a new validation for global variables and improved the way user IDs are retrieved by creating a new dedicated utility function. The updated function, getUserId, replaces the prior use of getServerSession across multiple files. The new approach is expected to streamline the user authentication process and reduce code redundancy. --- apps/nextjs/app/api/chat-with-vision/route.ts | 2 +- .../api/conversation2measurements/route.ts | 37 +++++++++++++++++++ apps/nextjs/app/api/dfda/[dfdaPath]/route.ts | 12 +++--- .../nextjs/app/api/text2measurements/route.ts | 13 +++---- apps/nextjs/lib/dfda.ts | 4 ++ apps/nextjs/lib/getUserId.ts | 6 +++ apps/nextjs/lib/useUserId.ts | 5 --- apps/nextjs/lib/validations/globalVariable.ts | 5 +++ 8 files changed, 64 insertions(+), 20 deletions(-) create mode 100644 apps/nextjs/app/api/conversation2measurements/route.ts create mode 100644 apps/nextjs/lib/getUserId.ts delete mode 100644 apps/nextjs/lib/useUserId.ts create mode 100644 apps/nextjs/lib/validations/globalVariable.ts diff --git a/apps/nextjs/app/api/chat-with-vision/route.ts b/apps/nextjs/app/api/chat-with-vision/route.ts index 5bee658e5..940801ba1 100644 --- a/apps/nextjs/app/api/chat-with-vision/route.ts +++ b/apps/nextjs/app/api/chat-with-vision/route.ts @@ -1,7 +1,7 @@ import OpenAI from 'openai'; import { OpenAIStream, StreamingTextResponse } from 'ai'; -// Create an OpenAI API client (that's edge friendly!) +// Create an OpenAI API client (that's edge-friendly!) const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY || '', }); diff --git a/apps/nextjs/app/api/conversation2measurements/route.ts b/apps/nextjs/app/api/conversation2measurements/route.ts new file mode 100644 index 000000000..d1f7edf92 --- /dev/null +++ b/apps/nextjs/app/api/conversation2measurements/route.ts @@ -0,0 +1,37 @@ +import { NextRequest, NextResponse } from 'next/server'; +import { conversation2measurements } from "@/lib/conversation2measurements"; +import {postMeasurements} from "@/lib/dfda"; +import {getUserId} from "@/lib/getUserId"; + +export async function POST(request: NextRequest) { + let { statement, localDateTime, previousStatements } = await request.json(); + +try { + const measurements = await conversation2measurements(statement, localDateTime, previousStatements); + const userId = await getUserId(); + if(userId){ + await postMeasurements(measurements, userId) + } + return NextResponse.json({ success: true, measurements: measurements }); + } catch (error) { + console.error('Error in conversation2measurements:', error); + return NextResponse.json({ success: false, message: 'Error in conversation2measurements' }); + } +} + +export async function GET(req: NextRequest) { + const urlParams = Object.fromEntries(new URL(req.url).searchParams); + const statement = urlParams.statement as string; + const previousStatements = urlParams.previousStatements as string | null | undefined; + const localDateTime = urlParams.localDateTime as string | null | undefined; + + try { + const measurements = await conversation2measurements(statement, localDateTime, previousStatements); + const userId = await getUserId(); + if(userId){await postMeasurements(measurements, userId)} + return NextResponse.json({ success: true, measurements: measurements }); + } catch (error) { + console.error('Error sending request to OpenAI:', error); + return NextResponse.json({ success: false, message: 'Error sending request to OpenAI' }); + } +} diff --git a/apps/nextjs/app/api/dfda/[dfdaPath]/route.ts b/apps/nextjs/app/api/dfda/[dfdaPath]/route.ts index 584a28425..ac9b341c7 100644 --- a/apps/nextjs/app/api/dfda/[dfdaPath]/route.ts +++ b/apps/nextjs/app/api/dfda/[dfdaPath]/route.ts @@ -1,9 +1,7 @@ -import { getServerSession } from 'next-auth/next'; import { z } from 'zod'; - -import { authOptions } from '@/lib/auth'; import { handleError } from '@/lib/errorHandler'; import {dfdaGET, dfdaPOST} from '@/lib/dfda'; +import {getUserId} from "@/lib/getUserId"; const routeContextSchema = z.object({ params: z.object({ @@ -14,9 +12,9 @@ const routeContextSchema = z.object({ export async function GET(req: Request, context: z.infer) { const { params } = routeContextSchema.parse(context); const urlParams = Object.fromEntries(new URL(req.url).searchParams); - const session = await getServerSession(authOptions); + const userId = await getUserId() try { - const response = await dfdaGET(params.dfdaPath, urlParams, session?.user.id); + const response = await dfdaGET(params.dfdaPath, urlParams, userId); const data = response.data ?? response; return new Response(JSON.stringify(data), { status: 200, headers: { 'Content-Type': 'application/json' } }); } catch (error) { @@ -28,9 +26,9 @@ export async function POST(req: Request, context: z.infer Date: Mon, 29 Apr 2024 20:09:21 -0600 Subject: [PATCH 2/4] Functionality for adding, editing, and displaying global variables, recording measurements, displaying charts, amongst others. Error handlers are also included if the CRUD operations fail. For better UX, loader spinners are added during fetch operations. --- .../[variableId]/charts/page.tsx | 34 ++++ .../[variableId]/not-found.tsx | 27 +++ .../globalVariables/[variableId]/page.tsx | 51 +++++ .../[variableId]/settings/page.tsx | 51 +++++ .../app/dashboard/globalVariables/page.tsx | 41 +++++ .../global-variable-add-button.tsx | 98 ++++++++++ .../global-variable-charts.tsx | 88 +++++++++ .../global-variable-edit-form.tsx | 125 +++++++++++++ .../globalVariables/global-variable-item.tsx | 87 +++++++++ .../global-variable-operations-button.tsx | 174 ++++++++++++++++++ .../global-variable-overview.tsx | 79 ++++++++ .../models/{Variable.ts => GlobalVariable.ts} | 4 +- apps/nextjs/types/models/ObjectSerializer.ts | 6 +- .../models/PostMeasurementsDataResponse.ts | 4 +- .../PostTrackingRemindersDataResponse.ts | 4 +- apps/nextjs/types/models/Study.ts | 6 +- apps/nextjs/types/models/all.ts | 2 +- 17 files changed, 868 insertions(+), 13 deletions(-) create mode 100644 apps/nextjs/app/dashboard/globalVariables/[variableId]/charts/page.tsx create mode 100644 apps/nextjs/app/dashboard/globalVariables/[variableId]/not-found.tsx create mode 100644 apps/nextjs/app/dashboard/globalVariables/[variableId]/page.tsx create mode 100644 apps/nextjs/app/dashboard/globalVariables/[variableId]/settings/page.tsx create mode 100644 apps/nextjs/app/dashboard/globalVariables/page.tsx create mode 100644 apps/nextjs/components/globalVariables/global-variable-add-button.tsx create mode 100644 apps/nextjs/components/globalVariables/global-variable-charts.tsx create mode 100644 apps/nextjs/components/globalVariables/global-variable-edit-form.tsx create mode 100644 apps/nextjs/components/globalVariables/global-variable-item.tsx create mode 100644 apps/nextjs/components/globalVariables/global-variable-operations-button.tsx create mode 100644 apps/nextjs/components/globalVariables/global-variable-overview.tsx rename apps/nextjs/types/models/{Variable.ts => GlobalVariable.ts} (99%) diff --git a/apps/nextjs/app/dashboard/globalVariables/[variableId]/charts/page.tsx b/apps/nextjs/app/dashboard/globalVariables/[variableId]/charts/page.tsx new file mode 100644 index 000000000..15b671ab4 --- /dev/null +++ b/apps/nextjs/app/dashboard/globalVariables/[variableId]/charts/page.tsx @@ -0,0 +1,34 @@ +import { Metadata } from "next" +import { notFound, redirect } from "next/navigation" + +import { authOptions } from "@/lib/auth" +import { getCurrentUser } from "@/lib/session" +import { Shell } from "@/components/layout/shell" +import { DashboardHeader } from "@/components/pages/dashboard/dashboard-header" +import { GlobalVariableCharts } from '@/components/globalVariables/global-variable-charts'; + +export const metadata: Metadata = { + title: "Global Variable Charts", +} + +interface GlobalVariableEditProps { + params: { variableId: string } +} + +export default async function GlobalVariableChart({ params }: GlobalVariableEditProps) { + const user = await getCurrentUser() + + if (!user) { + redirect(authOptions?.pages?.signIn || "/signin") + } + const variableId = parseInt(params.variableId) + return ( + +
+ +
+
+ ) +} diff --git a/apps/nextjs/app/dashboard/globalVariables/[variableId]/not-found.tsx b/apps/nextjs/app/dashboard/globalVariables/[variableId]/not-found.tsx new file mode 100644 index 000000000..c51b88727 --- /dev/null +++ b/apps/nextjs/app/dashboard/globalVariables/[variableId]/not-found.tsx @@ -0,0 +1,27 @@ +import Link from "next/link" + +import { buttonVariants } from "@/components/ui/button" +import { EmptyPlaceholder } from "@/components/empty-placeholder" +import { Icons } from "@/components/icons" + +export default function NotFound() { + return ( +
+ +
+ +
+ Not Found + + This globalVariable could not be found. Please try again. + + + Go to Dashboard + +
+
+ ) +} diff --git a/apps/nextjs/app/dashboard/globalVariables/[variableId]/page.tsx b/apps/nextjs/app/dashboard/globalVariables/[variableId]/page.tsx new file mode 100644 index 000000000..0fc45311c --- /dev/null +++ b/apps/nextjs/app/dashboard/globalVariables/[variableId]/page.tsx @@ -0,0 +1,51 @@ +import { Metadata } from "next" +import { redirect } from "next/navigation" + +import { authOptions } from "@/lib/auth" +import { getCurrentUser } from "@/lib/session" +import { Shell } from "@/components/layout/shell" +import { GlobalVariableOverview } from "@/components/globalVariables/global-variable-overview"; + + +interface GlobalVariablePageProps { + params: { variableId: number } + searchParams: { from: string; to: string } +} + +// export async function generateMetadata({ +// params, +// }: GlobalVariablePageProps): Promise { +// const user = await getCurrentUser() +// +// if (!user) { +// redirect(authOptions?.pages?.signIn || "/signin") +// } +// const response = await fetch(`/api/dfda/globalVariables?variableId=${params.variableId}&includeCharts=0`); +// const globalVariables = await response.json(); +// const globalVariable = globalVariables[0]; +// +// return { +// title: globalVariable?.name || "Not Found", +// description: globalVariable?.description, +// } +// } + +export default async function GlobalVariablePage({ + params, + searchParams, +}: GlobalVariablePageProps) { + const user = await getCurrentUser() + + if (!user) { + redirect(authOptions?.pages?.signIn || "/signin") + } + + return ( + + + + ) +} diff --git a/apps/nextjs/app/dashboard/globalVariables/[variableId]/settings/page.tsx b/apps/nextjs/app/dashboard/globalVariables/[variableId]/settings/page.tsx new file mode 100644 index 000000000..5aee0eeaf --- /dev/null +++ b/apps/nextjs/app/dashboard/globalVariables/[variableId]/settings/page.tsx @@ -0,0 +1,51 @@ +import { Metadata } from "next" +import { notFound, redirect } from "next/navigation" + +import { authOptions } from "@/lib/auth" +import { getCurrentUser } from "@/lib/session" +import { GlobalVariableEditForm } from "@/components/globalVariables/global-variable-edit-form" +import { Shell } from "@/components/layout/shell" +import { DashboardHeader } from "@/components/pages/dashboard/dashboard-header" + +export const metadata: Metadata = { + title: "GlobalVariable Settings", +} + +interface GlobalVariableEditProps { + params: { variableId: string } +} + +export default async function GlobalVariableEdit({ params }: GlobalVariableEditProps) { + const user = await getCurrentUser() + + if (!user) { + redirect(authOptions?.pages?.signIn || "/signin") + } + + const response = await fetch( + `/api/dfda/globalVariables?variableId=${params.variableId}&includeCharts=0`) + const globalVariables = await response.json() + const globalVariable = globalVariables[0] + + if (!globalVariable) { + notFound() + } + + return ( + + +
+ +
+
+ ) +} diff --git a/apps/nextjs/app/dashboard/globalVariables/page.tsx b/apps/nextjs/app/dashboard/globalVariables/page.tsx new file mode 100644 index 000000000..e1031112d --- /dev/null +++ b/apps/nextjs/app/dashboard/globalVariables/page.tsx @@ -0,0 +1,41 @@ +import { Metadata } from "next" +import { redirect } from "next/navigation" + +import { authOptions } from "@/lib/auth" +import { getCurrentUser } from "@/lib/session" +import { GlobalVariableAddButton } from "@/components/globalVariables/global-variable-add-button" +import { Shell } from "@/components/layout/shell" +import { DashboardHeader } from "@/components/pages/dashboard/dashboard-header" +import {GenericVariableList} from "@/components/genericVariables/generic-variable-list"; + + +export const metadata: Metadata = { + title: "Your Variables", + description: "Manage your treatments, symptoms, and other variables.", +} + +export default async function GlobalVariablesPage() { + const user = await getCurrentUser() + + if (!user) { + redirect(authOptions?.pages?.signIn || "/signin") + } + + // Define search parameters + const searchParams = { + includePublic: false, + sort: 'createdAt', + limit: 10, + offset: 0, + searchPhrase: "", + }; + + return ( + + + + + + + ) +} diff --git a/apps/nextjs/components/globalVariables/global-variable-add-button.tsx b/apps/nextjs/components/globalVariables/global-variable-add-button.tsx new file mode 100644 index 000000000..6b4681099 --- /dev/null +++ b/apps/nextjs/components/globalVariables/global-variable-add-button.tsx @@ -0,0 +1,98 @@ +"use client" + +import * as React from "react" +import { useRouter } from "next/navigation" + +import { Button, ButtonProps } from "@/components/ui/button" +import { + Credenza, + CredenzaClose, + CredenzaContent, + CredenzaDescription, + CredenzaFooter, + CredenzaHeader, + CredenzaTitle, +} from "@/components/ui/credenza" +import { toast } from "@/components/ui/use-toast" +import { Icons } from "@/components/icons" + +interface GlobalVariableAddButtonProps extends ButtonProps {} + +export function GlobalVariableAddButton({ ...props }: GlobalVariableAddButtonProps) { + const router = useRouter() + const [showAddAlert, setShowAddAlert] = React.useState(false) + const [isLoading, setIsLoading] = React.useState(false) + + async function onClick() { + setIsLoading(true) + + const response = await fetch("/api/globalVariables", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + name: "New Variable", + }), + }) + + if (!response?.ok) { + setIsLoading(false) + setShowAddAlert(false) + + return toast({ + title: "Something went wrong.", + description: "Your globalVariable was not created. Please try again.", + variant: "destructive", + }) + } + + toast({ + description: "A new variable has been created successfully.", + }) + + const globalVariable = await response.json() + + setIsLoading(false) + setShowAddAlert(false) + + router.push(`/dashboard/globalVariables/${globalVariable.id}/settings`) + router.refresh() + } + + return ( + <> + + + {/* Add Alert */} + + + + + Are you sure you want to create a new variable? + + + This will add a new variable to your account. + + + + + + + + + + + + ) +} diff --git a/apps/nextjs/components/globalVariables/global-variable-charts.tsx b/apps/nextjs/components/globalVariables/global-variable-charts.tsx new file mode 100644 index 000000000..89e16a039 --- /dev/null +++ b/apps/nextjs/components/globalVariables/global-variable-charts.tsx @@ -0,0 +1,88 @@ +"use client" + +import * as React from "react" +import { FC } from 'react'; +import HighchartsReact from 'highcharts-react-official'; +import Highcharts from 'highcharts'; +// TODO: Fix highcharts accessibility +// import highchartsAccessibility from "highcharts/modules/accessibility"; +// if (typeof window !== undefined) { +// highchartsAccessibility(Highcharts); +// } + +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card" +import { GlobalVariable as GlobalVariable } from "@/types/models/GlobalVariable"; +import { useEffect, useState } from 'react'; +import { Icons } from "../icons"; + +interface GlobalVariableChartsProps extends React.HTMLAttributes { + variableId: number +} + +export const GlobalVariableCharts: FC = ({ variableId }) => { + const [globalVariable, setGlobalVariable] = useState(); + const [isLoading, setIsLoading] = useState(true); // Add a loading state + + useEffect(() => { + const url = `/api/dfda/globalVariables?variableId=${variableId}&includeCharts=1`; + + setIsLoading(true); // Set loading to true when the fetch starts + fetch(url) + .then(response => response.json()) + .then(globalVariables => { + const globalVariable = globalVariables[0]; + delete globalVariable.charts.lineChartWithSmoothing.highchartConfig.tooltip.formatter; + delete globalVariable.charts.weekdayColumnChart.highchartConfig.tooltip.formatter; + delete globalVariable.charts.monthlyColumnChart.highchartConfig.tooltip.formatter; + setGlobalVariable(globalVariable); + setIsLoading(false); // Set loading to false when the fetch completes + }) + .catch(error => { + console.error('Error fetching user variables:', error); + setIsLoading(false); // Ensure loading is set to false on error as well + }); + + }, [variableId]); + + return ( + + + {globalVariable?.name} + {globalVariable?.description && ( + {globalVariable.description} + )} + + {isLoading ? ( +
+ +
+ ) : ( + +
+ + + +
+
+ )} + + +
+ ) +} diff --git a/apps/nextjs/components/globalVariables/global-variable-edit-form.tsx b/apps/nextjs/components/globalVariables/global-variable-edit-form.tsx new file mode 100644 index 000000000..d3a628b3a --- /dev/null +++ b/apps/nextjs/components/globalVariables/global-variable-edit-form.tsx @@ -0,0 +1,125 @@ +"use client" + +import * as React from "react" +import { useRouter } from "next/navigation" +import { zodResolver } from "@hookform/resolvers/zod" +import { useForm } from "react-hook-form" +import * as z from "zod" + +import { cn } from "@/lib/utils" +import { buttonVariants } from "@/components/ui/button" +import { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +} from "@/components/ui/card" +import { Input } from "@/components/ui/input" +import { Label } from "@/components/ui/label" +import { Textarea } from "@/components/ui/textarea" +import { toast } from "@/components/ui/use-toast" +import { Icons } from "@/components/icons" +import { GlobalVariable as GlobalVariable } from "@/types/models/GlobalVariable"; +import {globalVariablePatchSchema} from "@/lib/validations/globalVariable"; + +interface GlobalVariableEditFormProps extends React.HTMLAttributes { + globalVariable: Pick +} + +type FormData = z.infer + +export function GlobalVariableEditForm({ + globalVariable, + className, + ...props +}: GlobalVariableEditFormProps) { + const router = useRouter() + const { + handleSubmit, + register, + formState: { errors, isSubmitting }, + } = useForm({ + resolver: zodResolver(globalVariablePatchSchema), + defaultValues: { + name: globalVariable?.name || "", + }, + }) + + async function onSubmit(data: FormData) { + const response = await fetch(`/api/globalVariables/${globalVariable.id}`, { + method: "PATCH", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + name: data.name, + }), + }) + + if (!response?.ok) { + return toast({ + title: "Something went wrong.", + description: "Your globalVariable was not updated. Please try again.", + variant: "destructive", + }) + } + + toast({ + description: "Your globalVariable has been updated.", + }) + + router.back() + router.refresh() + } + + return ( +
+ + + {globalVariable.name} + {globalVariable.description && ( + {globalVariable.description} + )} + + +
+ + + {errors?.name && ( +

{errors.name.message}

+ )} +
+
+ +
+
+ + + +
+
+ ) +} diff --git a/apps/nextjs/components/globalVariables/global-variable-item.tsx b/apps/nextjs/components/globalVariables/global-variable-item.tsx new file mode 100644 index 000000000..eee006215 --- /dev/null +++ b/apps/nextjs/components/globalVariables/global-variable-item.tsx @@ -0,0 +1,87 @@ +"use client" + +import Link from "next/link" + +import { Skeleton } from "@/components/ui/skeleton" +import { GlobalVariableOperationsButton } from "@/components/globalVariables/global-variable-operations-button" +import { QuickMeasurementButton } from '@/components/measurements/quick-measurement-button'; +import { MeasurementButton } from '@/components/measurements/measurement-button'; +import { GlobalVariable as GlobalVariable } from "@/types/models/GlobalVariable"; +import { Icons } from "../icons"; +import {Button} from "@/components/ui/button"; + +interface GlobalVariableItemProps { + globalVariable: GlobalVariable; +} +export function GlobalVariableItem({ globalVariable }: GlobalVariableItemProps) { + return ( +
+
+ +
+ {globalVariable.imageUrl && ( + {globalVariable.name} + )} +
+ + {globalVariable.name} + +{/*
+

+ {formatDate(globalVariable.createdAt?.toDateString())} +

+
*/} +
+
+{/* {globalVariable.description ? ( +
+ {globalVariable.description} +
+ ) : null}*/} +
+
+ + + + + + + + + +
+
+ ) +} + +GlobalVariableItem.Skeleton = function GlobalVariableItemSkeleton() { + return ( +
+
+ + +
+
+ ) +} diff --git a/apps/nextjs/components/globalVariables/global-variable-operations-button.tsx b/apps/nextjs/components/globalVariables/global-variable-operations-button.tsx new file mode 100644 index 000000000..53de0ceee --- /dev/null +++ b/apps/nextjs/components/globalVariables/global-variable-operations-button.tsx @@ -0,0 +1,174 @@ +"use client" + +import * as React from "react" +import Link from "next/link" +import { useRouter } from "next/navigation" + +import { Button } from "@/components/ui/button" +import { + Credenza, + CredenzaClose, + CredenzaContent, + CredenzaDescription, + CredenzaFooter, + CredenzaHeader, + CredenzaTitle, +} from "@/components/ui/credenza" +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu" +import { toast } from "@/components/ui/use-toast" +import { Icons } from "@/components/icons" + +import { MeasurementsAddForm } from "@/components/measurements/measurements-add-form" +import { GlobalVariable as GlobalVariable } from "@/types/models/GlobalVariable"; + +async function deleteGlobalVariable(globalVariableId: number) { + const response = await fetch(`/api/globalVariables/${globalVariableId}`, { + method: "DELETE", + }) + + if (!response?.ok) { + toast({ + title: "Something went wrong.", + description: "Your globalVariable was not deleted. Please try again.", + variant: "destructive", + }) + } else { + toast({ + description: "Your globalVariable has been deleted successfully.", + }) + } + + return true +} + +interface GlobalVariableOperationsProps { + globalVariable: GlobalVariable; + children?: React.ReactNode +} + +export function GlobalVariableOperationsButton({ + globalVariable, + children, +}: GlobalVariableOperationsProps) { + const router = useRouter() + const [showDeleteAlert, setShowDeleteAlert] = React.useState(false) + const [isDeleteLoading, setIsDeleteLoading] = React.useState(false) + const [showMeasurementAlert, setShowMeasurementAlert] = React.useState(false) + const [showDropDown, setShowDropDown] = React.useState(false) + + return ( + <> + + + {children ? ( + children + ) : ( +
+ + Open +
+ )} +
+ + { + setShowMeasurementAlert(true) + setShowDropDown(false) + }} + > + + Record Measurement + + + + + + Settings + + + + { + setShowDeleteAlert(true) + setShowDropDown(false) + }} + > + + Delete + + +
+ + {/* Add Alert */} + + + + Record a Measurement + + This will record a {globalVariable.name} measurement. + + + + + + + {/* Delete Alert */} + + + + + Are you sure you want to delete this globalVariable? + + + This action cannot be undone. + + + + + + + + + + + + ) +} diff --git a/apps/nextjs/components/globalVariables/global-variable-overview.tsx b/apps/nextjs/components/globalVariables/global-variable-overview.tsx new file mode 100644 index 000000000..a336f10b0 --- /dev/null +++ b/apps/nextjs/components/globalVariables/global-variable-overview.tsx @@ -0,0 +1,79 @@ +"use client"; +import { Icons } from "@/components/icons"; +import { FC, useEffect, useState } from "react"; +import { GlobalVariable as GlobalVariable } from "@/types/models/GlobalVariable"; +import { DashboardHeader } from "@/components/pages/dashboard/dashboard-header"; +import { DateRangePicker } from "@/components/date-range-picker"; +import { GlobalVariableOperationsButton } from "@/components/globalVariables/global-variable-operations-button"; +import { cn } from "@/lib/utils"; +import { buttonVariants } from "@/components/ui/button"; +import { MeasurementsList } from "@/components/measurements/measurements-list"; +import * as React from "react"; +type GlobalVariableOverviewProps = { + user: { + id: string; + }; + variableId: number; + measurementsDateRange: { + from: string; + to: string; + }; +}; + +export const GlobalVariableOverview: FC = ({ user, variableId, measurementsDateRange }) => { + + const [globalVariable, setGlobalVariable] = useState(); + const [isLoading, setIsLoading] = useState(true); // Add a loading state + + useEffect(() => { + setIsLoading(true); // Set loading to true when starting to fetch + const url = `/api/dfda/variables?variableId=${variableId}`; + + fetch(url) + .then(response => response.json()) + .then(globalVariables => { + setGlobalVariable(globalVariables[0]); + setIsLoading(false); // Set loading to false once data is fetched + }) + .catch(error => { + console.error('Error fetching user variables:', error); + setIsLoading(false); // Ensure loading is set to false even if there's an error + }); + + }, [user, variableId]); + + if (isLoading) { + return
+ +
; + } + + // Ensure globalVariable is defined before trying to access its properties + if (!globalVariable) { + return
No data found.
; // Handle the case where globalVariable is undefined + } + + return ( + <> + +
+ + +
+ + Actions +
+
+
+
+ + + ) +} diff --git a/apps/nextjs/types/models/Variable.ts b/apps/nextjs/types/models/GlobalVariable.ts similarity index 99% rename from apps/nextjs/types/models/Variable.ts rename to apps/nextjs/types/models/GlobalVariable.ts index 61e3f0fd8..e7dd50860 100644 --- a/apps/nextjs/types/models/Variable.ts +++ b/apps/nextjs/types/models/GlobalVariable.ts @@ -19,7 +19,7 @@ import { VariableCategory } from '../models/VariableCategory'; import { VariableCharts } from '../models/VariableCharts'; -export class Variable { +export class GlobalVariable { 'actionArray'?: Array; /** * User-Defined Variable Setting: Alternative display name @@ -1498,7 +1498,7 @@ export class Variable { } ]; static getAttributeTypeMap() { - return Variable.attributeTypeMap; + return GlobalVariable.attributeTypeMap; } public constructor() { diff --git a/apps/nextjs/types/models/ObjectSerializer.ts b/apps/nextjs/types/models/ObjectSerializer.ts index 4a5181f27..65102822f 100644 --- a/apps/nextjs/types/models/ObjectSerializer.ts +++ b/apps/nextjs/types/models/ObjectSerializer.ts @@ -62,7 +62,7 @@ export * from '../models/UserTag'; export * from '../models/UserVariable'; export * from '../models/UserVariableDelete'; export * from '../models/UsersResponse'; -export * from '../models/Variable'; +export * from './GlobalVariable'; export * from '../models/VariableCategory'; export * from '../models/VariableCharts'; export * from '../models/Vote'; @@ -131,7 +131,7 @@ import { UserTag } from '../models/UserTag'; import { UserVariable , UserVariableCombinationOperationEnum , UserVariableFillingTypeEnum , UserVariableVariableCategoryNameEnum } from '../models/UserVariable'; import { UserVariableDelete } from '../models/UserVariableDelete'; import { UsersResponse } from '../models/UsersResponse'; -import { Variable , VariableCombinationOperationEnum , VariableFillingTypeEnum , VariableVariableCategoryNameEnum } from '../models/Variable'; +import { GlobalVariable , VariableCombinationOperationEnum , VariableFillingTypeEnum , VariableVariableCategoryNameEnum } from './GlobalVariable'; import { VariableCategory , VariableCategoryVariableCategoryNameEnum } from '../models/VariableCategory'; import { VariableCharts } from '../models/VariableCharts'; import { Vote , VoteValueEnum , VoteTypeEnum } from '../models/Vote'; @@ -247,7 +247,7 @@ let typeMap: {[index: string]: any} = { "UserVariable": UserVariable, "UserVariableDelete": UserVariableDelete, "UsersResponse": UsersResponse, - "Variable": Variable, + "Variable": GlobalVariable, "VariableCategory": VariableCategory, "VariableCharts": VariableCharts, "Vote": Vote, diff --git a/apps/nextjs/types/models/PostMeasurementsDataResponse.ts b/apps/nextjs/types/models/PostMeasurementsDataResponse.ts index 210e23b13..8cfc91c30 100644 --- a/apps/nextjs/types/models/PostMeasurementsDataResponse.ts +++ b/apps/nextjs/types/models/PostMeasurementsDataResponse.ts @@ -12,11 +12,11 @@ import { Card } from '../models/Card'; import { ErrorResponse } from '../models/ErrorResponse'; -import { Variable } from '../models/Variable'; +import { GlobalVariable } from './GlobalVariable'; export class PostMeasurementsDataResponse { - 'userVariables'?: Array; + 'userVariables'?: Array; /** * Can be used as body of help info popup */ diff --git a/apps/nextjs/types/models/PostTrackingRemindersDataResponse.ts b/apps/nextjs/types/models/PostTrackingRemindersDataResponse.ts index 63f8b08b0..19ef1cac6 100644 --- a/apps/nextjs/types/models/PostTrackingRemindersDataResponse.ts +++ b/apps/nextjs/types/models/PostTrackingRemindersDataResponse.ts @@ -14,13 +14,13 @@ import { Card } from '../models/Card'; import { ErrorResponse } from '../models/ErrorResponse'; import { TrackingReminder } from '../models/TrackingReminder'; import { TrackingReminderNotification } from '../models/TrackingReminderNotification'; -import { Variable } from '../models/Variable'; +import { GlobalVariable } from './GlobalVariable'; export class PostTrackingRemindersDataResponse { 'trackingReminderNotifications'?: Array; 'trackingReminders'?: Array; - 'userVariables'?: Array; + 'userVariables'?: Array; /** * Can be used as body of help info popup */ diff --git a/apps/nextjs/types/models/Study.ts b/apps/nextjs/types/models/Study.ts index 617c7bd5c..4df726798 100644 --- a/apps/nextjs/types/models/Study.ts +++ b/apps/nextjs/types/models/Study.ts @@ -20,7 +20,7 @@ import { StudyLinks } from '../models/StudyLinks'; import { StudySharing } from '../models/StudySharing'; import { StudyText } from '../models/StudyText'; import { StudyVotes } from '../models/StudyVotes'; -import { Variable } from '../models/Variable'; +import { GlobalVariable } from './GlobalVariable'; /** @@ -39,13 +39,13 @@ export class Study { * ID of the cohort study which is necessary to allow participants to join */ 'id'?: string; - 'causeVariable'?: Variable; + 'causeVariable'?: GlobalVariable; /** * Ex: Sleep Quality */ 'causeVariableName'?: string; 'studyCharts'?: StudyCharts; - 'effectVariable'?: Variable; + 'effectVariable'?: GlobalVariable; /** * Ex: Overall Mood */ diff --git a/apps/nextjs/types/models/all.ts b/apps/nextjs/types/models/all.ts index cc8087222..1a6fde539 100644 --- a/apps/nextjs/types/models/all.ts +++ b/apps/nextjs/types/models/all.ts @@ -62,7 +62,7 @@ export * from '../models/UserTag' export * from '../models/UserVariable' export * from '../models/UserVariableDelete' export * from '../models/UsersResponse' -export * from '../models/Variable' +export * from './GlobalVariable' export * from '../models/VariableCategory' export * from '../models/VariableCharts' export * from '../models/Vote' From 52a743c524063c1da2f2554887c4550fdd79e10c Mon Sep 17 00:00:00 2001 From: "Mike P. Sinn" Date: Mon, 29 Apr 2024 20:10:55 -0600 Subject: [PATCH 3/4] Measurements components and updated the variable types from being exclusively tied to 'UserVariable' to also catering 'GlobalVariable'. This refactoring aids in managing code organization and improves components' scalability by incorporating more generic variable types. --- .../app/dashboard/measurements/page.tsx | 2 +- .../measurement-button.tsx | 21 +++++++------- .../measurement-delete-button.tsx | 0 .../measurements/measurements-add-form.tsx | 29 ++++++++++--------- .../measurements/measurements-columns.tsx | 0 .../measurements/measurements-list.tsx | 8 +++-- .../measurements/quick-measurement-button.tsx | 23 +++++++++------ 7 files changed, 47 insertions(+), 36 deletions(-) rename apps/nextjs/components/{userVariable => measurements}/measurement-button.tsx (69%) rename apps/nextjs/components/{userVariable => }/measurements/measurement-delete-button.tsx (100%) rename apps/nextjs/components/{userVariable => }/measurements/measurements-add-form.tsx (88%) rename apps/nextjs/components/{userVariable => }/measurements/measurements-columns.tsx (100%) rename apps/nextjs/components/{userVariable => }/measurements/measurements-list.tsx (90%) rename apps/nextjs/components/{userVariable => }/measurements/quick-measurement-button.tsx (71%) diff --git a/apps/nextjs/app/dashboard/measurements/page.tsx b/apps/nextjs/app/dashboard/measurements/page.tsx index 05454b30c..352889e22 100644 --- a/apps/nextjs/app/dashboard/measurements/page.tsx +++ b/apps/nextjs/app/dashboard/measurements/page.tsx @@ -5,7 +5,7 @@ import { getCurrentUser } from "@/lib/session" import { Shell } from "@/components/layout/shell" import {DashboardHeader} from "@/components/pages/dashboard/dashboard-header"; import {DateRangePicker} from "@/components/date-range-picker"; -import {MeasurementsList} from "@/components/userVariable/measurements/measurements-list"; +import {MeasurementsList} from "@/components/measurements/measurements-list"; interface MeasurementsPageProps { diff --git a/apps/nextjs/components/userVariable/measurement-button.tsx b/apps/nextjs/components/measurements/measurement-button.tsx similarity index 69% rename from apps/nextjs/components/userVariable/measurement-button.tsx rename to apps/nextjs/components/measurements/measurement-button.tsx index 34d2dc23c..c1dbbaa12 100644 --- a/apps/nextjs/components/userVariable/measurement-button.tsx +++ b/apps/nextjs/components/measurements/measurement-button.tsx @@ -8,23 +8,24 @@ import { CredenzaHeader, CredenzaTitle } from '@/components/ui/credenza'; -import {MeasurementsAddForm} from "@/components/userVariable/measurements/measurements-add-form"; +import {MeasurementsAddForm} from "@/components/measurements/measurements-add-form"; import {UserVariable} from "@/types/models/UserVariable"; import {Icons} from "@/components/icons"; import {ButtonProps} from 'react-day-picker'; +import {GlobalVariable} from "@/types/models/GlobalVariable"; interface MeasurementButtonProps extends ButtonProps { - userVariable: Pick< - UserVariable, + genericVariable: Pick< + UserVariable | GlobalVariable, "id" | "name" | "description" | "createdAt" | "imageUrl" | "combinationOperation" | "unitAbbreviatedName" | "variableCategoryName" | "lastValue" | "unitName" | "userId" | "variableId" >, - variant?: string, - size?: string + variant?: "default" | "link" | "destructive" | "outline" | "secondary" | "ghost" | null | undefined, + size?: "default" | "sm" | "lg" | "icon" | null | undefined } -export function MeasurementButton({userVariable, variant, size, ...props}: MeasurementButtonProps) { +export function MeasurementButton({genericVariable, variant, size, ...props}: MeasurementButtonProps) { const {ref, ...rest} = props; // Destructure out `ref` and spread the rest const [isFormOpen, setIsFormOpen] = useState(false); @@ -37,13 +38,13 @@ export function MeasurementButton({userVariable, variant, size, ...props}: Measu return ( <> - {isFormOpen && ( @@ -53,11 +54,11 @@ export function MeasurementButton({userVariable, variant, size, ...props}: Measu Record a Measurement - This will record a {userVariable.name} measurement. + This will record a {genericVariable.name} measurement. diff --git a/apps/nextjs/components/userVariable/measurements/measurement-delete-button.tsx b/apps/nextjs/components/measurements/measurement-delete-button.tsx similarity index 100% rename from apps/nextjs/components/userVariable/measurements/measurement-delete-button.tsx rename to apps/nextjs/components/measurements/measurement-delete-button.tsx diff --git a/apps/nextjs/components/userVariable/measurements/measurements-add-form.tsx b/apps/nextjs/components/measurements/measurements-add-form.tsx similarity index 88% rename from apps/nextjs/components/userVariable/measurements/measurements-add-form.tsx rename to apps/nextjs/components/measurements/measurements-add-form.tsx index 268bdd014..c87190152 100644 --- a/apps/nextjs/components/userVariable/measurements/measurements-add-form.tsx +++ b/apps/nextjs/components/measurements/measurements-add-form.tsx @@ -27,10 +27,11 @@ import { } from '@/components/ui/popover'; import { toast } from '@/components/ui/use-toast'; import { Icons } from '@/components/icons'; -import { UserVariable } from '@/types/models/UserVariable'; +import {GlobalVariable as GlobalVariable} from '@/types/models/GlobalVariable'; +import {UserVariable} from "@/types/models/UserVariable"; interface MeasurementsAddFormProps { - userVariable: UserVariable; + genericVariable: GlobalVariable | UserVariable; setShowMeasurementAlert: (active: boolean) => void; } @@ -87,21 +88,21 @@ const ratingButtons: Record>({ resolver: zodResolver(FormSchema), defaultValues: { date: currentDate, - value: userVariable.mostCommonValue // Set default value to userVariable.mostCommonValue + value: genericVariable.mostCommonValue // Set default value to genericVariable.mostCommonValue } }); const [isLoading, setIsLoading] = React.useState(false); - const valence = userVariable.valence; + const valence = genericVariable.valence; let buttons = null; - if(userVariable.unitAbbreviatedName === '/5' && ratingButtons[valence as Valence]) { + if(genericVariable.unitAbbreviatedName === '/5' && ratingButtons[valence as Valence]) { buttons = ratingButtons[valence as Valence]; } @@ -121,21 +122,21 @@ export function MeasurementsAddForm({ userVariable, setShowMeasurementAlert }: M body: JSON.stringify({ startAt: data.date, value: data.value, // Use the value from the form - variableId: userVariable.variableId + variableId: genericVariable.variableId }) }); if (!response?.ok) { toast({ title: 'Something went wrong.', - description: userVariable.name + ' was not recorded. Please try again.', + description: genericVariable.name + ' was not recorded. Please try again.', variant: 'destructive' }); } else { toast({ description: 'Recorded ' + data.value + ' ' + - userVariable.unitAbbreviatedName + ' for ' + - userVariable.name + ' on ' + + genericVariable.unitAbbreviatedName + ' for ' + + genericVariable.name + ' on ' + format(data.date, 'PPP') }); } @@ -216,18 +217,18 @@ export function MeasurementsAddForm({ userVariable, setShowMeasurementAlert }: M name="value" render={({ field }) => ( - {userVariable.name} Value + {genericVariable.name} Value
- {userVariable.unitAbbreviatedName} + {genericVariable.unitAbbreviatedName}
diff --git a/apps/nextjs/components/userVariable/measurements/measurements-columns.tsx b/apps/nextjs/components/measurements/measurements-columns.tsx similarity index 100% rename from apps/nextjs/components/userVariable/measurements/measurements-columns.tsx rename to apps/nextjs/components/measurements/measurements-columns.tsx diff --git a/apps/nextjs/components/userVariable/measurements/measurements-list.tsx b/apps/nextjs/components/measurements/measurements-list.tsx similarity index 90% rename from apps/nextjs/components/userVariable/measurements/measurements-list.tsx rename to apps/nextjs/components/measurements/measurements-list.tsx index fe220d7bc..6b07a2993 100644 --- a/apps/nextjs/components/userVariable/measurements/measurements-list.tsx +++ b/apps/nextjs/components/measurements/measurements-list.tsx @@ -2,7 +2,9 @@ import { FC, useState, useEffect } from "react"; import { Measurement } from "@/types/models/Measurement"; import { DataTable } from "@/components/data-table"; -import { measurementColumns } from "@/components/userVariable/measurements/measurements-columns"; +import { measurementColumns } from "@/components/measurements/measurements-columns"; +import {Icons} from "@/components/icons"; +import * as React from "react"; type MeasurementsListProps = { user: { @@ -62,7 +64,9 @@ export const MeasurementsList: FC = ({ user, variableId, }, [user, variableId, measurementsDateRange.from, measurementsDateRange.to]); if (isLoading) { - return
Loading...
; // Show a loader or a loading component + return
+ +
; } // Ensure measurements are defined before trying to access its properties diff --git a/apps/nextjs/components/userVariable/measurements/quick-measurement-button.tsx b/apps/nextjs/components/measurements/quick-measurement-button.tsx similarity index 71% rename from apps/nextjs/components/userVariable/measurements/quick-measurement-button.tsx rename to apps/nextjs/components/measurements/quick-measurement-button.tsx index 7c892134e..8bc77fb34 100644 --- a/apps/nextjs/components/userVariable/measurements/quick-measurement-button.tsx +++ b/apps/nextjs/components/measurements/quick-measurement-button.tsx @@ -7,17 +7,18 @@ import { Button, ButtonProps } from "@/components/ui/button" import { toast } from "@/components/ui/use-toast" import { Icons } from "@/components/icons" import { UserVariable } from "@/types/models/UserVariable"; +import {GlobalVariable} from "@/types/models/GlobalVariable"; interface QuickMeasurementButtonProps extends ButtonProps { - userVariable: Pick< - UserVariable, + genericVariable: Pick< + UserVariable | GlobalVariable, "id" | "name" | "description" | "createdAt" | "imageUrl" | "combinationOperation" | "unitAbbreviatedName" | "variableCategoryName" | "lastValue" | "unitName" > } -export function QuickMeasurementButton({ userVariable, ...props }: QuickMeasurementButtonProps) { +export function QuickMeasurementButton({ genericVariable, ...props }: QuickMeasurementButtonProps) { const router = useRouter() const [isLoading, setIsLoading] = React.useState(false) @@ -34,11 +35,11 @@ export function QuickMeasurementButton({ userVariable, ...props }: QuickMeasurem }, body: JSON.stringify({ startAt: dateToday, - value: userVariable.lastValue, - variableId: userVariable.name, - variableCategoryName: userVariable.variableCategoryName, - combinationOperation: userVariable.combinationOperation, - unitAbbreviatedName: userVariable.unitAbbreviatedName, + value: genericVariable.lastValue, + variableId: genericVariable.name, + variableCategoryName: genericVariable.variableCategoryName, + combinationOperation: genericVariable.combinationOperation, + unitAbbreviatedName: genericVariable.unitAbbreviatedName, }), }) @@ -59,6 +60,10 @@ export function QuickMeasurementButton({ userVariable, ...props }: QuickMeasurem router.refresh() } + if(!genericVariable) { + debugger + } + return ( From e14b69a318e591e6f0e9cdde1805c7f653c84ece Mon Sep 17 00:00:00 2001 From: "Mike P. Sinn" Date: Mon, 29 Apr 2024 20:11:44 -0600 Subject: [PATCH 4/4] Refactor user variable components and improve loading state Components related to user variables have been refactored from 'userVariable' to 'genericVariables' or 'userVariables' to maintain consistency. The loading state for 'user-variable-overview' and 'generic-variable-list' has been modified to show a spinning icon for better user experience. Optional parameters with default values have been added to 'GenericVariableSearch'. --- apps/nextjs/app/dashboard/page.tsx | 6 +++--- .../userVariables/[variableId]/charts/page.tsx | 2 +- .../userVariables/[variableId]/page.tsx | 2 +- .../userVariables/[variableId]/settings/page.tsx | 2 +- apps/nextjs/app/dashboard/userVariables/page.tsx | 10 +++++----- apps/nextjs/components/RemoteMdxLoader.tsx | 14 ++++++++++---- .../generic-variable-list.tsx} | 16 ++++++++-------- .../generic-variable-search.tsx} | 12 +++++++----- .../stats/stats-cards.tsx | 0 .../user-variable-add-button.tsx | 0 .../user-variable-charts.tsx | 0 .../user-variable-edit-form.tsx | 0 .../user-variable-item.tsx | 13 +++++++------ .../user-variable-operations-button.tsx | 4 ++-- .../user-variable-overview.tsx | 9 ++++++--- 15 files changed, 51 insertions(+), 39 deletions(-) rename apps/nextjs/components/{userVariable/user-variable-list.tsx => genericVariables/generic-variable-list.tsx} (83%) rename apps/nextjs/components/{userVariable/user-variable-search.tsx => genericVariables/generic-variable-search.tsx} (73%) rename apps/nextjs/components/{userVariable => userVariables}/stats/stats-cards.tsx (100%) rename apps/nextjs/components/{userVariable => userVariables}/user-variable-add-button.tsx (100%) rename apps/nextjs/components/{userVariable => userVariables}/user-variable-charts.tsx (100%) rename apps/nextjs/components/{userVariable => userVariables}/user-variable-edit-form.tsx (100%) rename apps/nextjs/components/{userVariable => userVariables}/user-variable-item.tsx (88%) rename apps/nextjs/components/{userVariable => userVariables}/user-variable-operations-button.tsx (97%) rename apps/nextjs/components/{userVariable => userVariables}/user-variable-overview.tsx (89%) diff --git a/apps/nextjs/app/dashboard/page.tsx b/apps/nextjs/app/dashboard/page.tsx index 9a2b0176c..8a00f6534 100644 --- a/apps/nextjs/app/dashboard/page.tsx +++ b/apps/nextjs/app/dashboard/page.tsx @@ -6,7 +6,7 @@ import { getCurrentUser } from "@/lib/session" import { Shell } from "@/components/layout/shell" import { DashboardHeader } from "@/components/pages/dashboard/dashboard-header" -import {UserVariableSearch} from "@/components/userVariable/user-variable-search"; +import {GenericVariableSearch} from "@/components/genericVariables/generic-variable-search"; export const metadata: Metadata = { title: "Dashboard", @@ -25,10 +25,10 @@ export default async function Dashboard() { return ( - +
- +
) diff --git a/apps/nextjs/app/dashboard/userVariables/[variableId]/charts/page.tsx b/apps/nextjs/app/dashboard/userVariables/[variableId]/charts/page.tsx index b9ce75254..db7049175 100644 --- a/apps/nextjs/app/dashboard/userVariables/[variableId]/charts/page.tsx +++ b/apps/nextjs/app/dashboard/userVariables/[variableId]/charts/page.tsx @@ -5,7 +5,7 @@ import { authOptions } from "@/lib/auth" import { getCurrentUser } from "@/lib/session" import { Shell } from "@/components/layout/shell" import { DashboardHeader } from "@/components/pages/dashboard/dashboard-header" -import { UserVariableCharts } from '@/components/userVariable/user-variable-charts'; +import { UserVariableCharts } from '@/components/userVariables/user-variable-charts'; export const metadata: Metadata = { title: "UserVariable Charts", diff --git a/apps/nextjs/app/dashboard/userVariables/[variableId]/page.tsx b/apps/nextjs/app/dashboard/userVariables/[variableId]/page.tsx index 191ff3880..5264a57c4 100644 --- a/apps/nextjs/app/dashboard/userVariables/[variableId]/page.tsx +++ b/apps/nextjs/app/dashboard/userVariables/[variableId]/page.tsx @@ -4,7 +4,7 @@ import { redirect } from "next/navigation" import { authOptions } from "@/lib/auth" import { getCurrentUser } from "@/lib/session" import { Shell } from "@/components/layout/shell" -import { UserVariableOverview } from "@/components/userVariable/user-variable-overview"; +import { UserVariableOverview } from "@/components/userVariables/user-variable-overview"; interface UserVariablePageProps { diff --git a/apps/nextjs/app/dashboard/userVariables/[variableId]/settings/page.tsx b/apps/nextjs/app/dashboard/userVariables/[variableId]/settings/page.tsx index 002bf82b4..f4779cbdb 100644 --- a/apps/nextjs/app/dashboard/userVariables/[variableId]/settings/page.tsx +++ b/apps/nextjs/app/dashboard/userVariables/[variableId]/settings/page.tsx @@ -3,7 +3,7 @@ import { notFound, redirect } from "next/navigation" import { authOptions } from "@/lib/auth" import { getCurrentUser } from "@/lib/session" -import { UserVariableEditForm } from "@/components/userVariable/user-variable-edit-form" +import { UserVariableEditForm } from "@/components/userVariables/user-variable-edit-form" import { Shell } from "@/components/layout/shell" import { DashboardHeader } from "@/components/pages/dashboard/dashboard-header" diff --git a/apps/nextjs/app/dashboard/userVariables/page.tsx b/apps/nextjs/app/dashboard/userVariables/page.tsx index ff6328d97..90b5e9a26 100644 --- a/apps/nextjs/app/dashboard/userVariables/page.tsx +++ b/apps/nextjs/app/dashboard/userVariables/page.tsx @@ -3,8 +3,8 @@ import { redirect } from "next/navigation" import { authOptions } from "@/lib/auth" import { getCurrentUser } from "@/lib/session" -import { UserVariableAddButton } from "@/components/userVariable/user-variable-add-button" -import { UserVariableList } from "@/components/userVariable/user-variable-list" +import { UserVariableAddButton } from "@/components/userVariables/user-variable-add-button" +import { GenericVariableList } from "@/components/genericVariables/generic-variable-list" import { Shell } from "@/components/layout/shell" import { DashboardHeader } from "@/components/pages/dashboard/dashboard-header" @@ -24,10 +24,10 @@ export default async function UserVariablesPage() { // Define search parameters const searchParams = { includePublic: false, - sort: 'createdAt', + sort: '-updatedAt', limit: 10, offset: 0, - searchPhrase: "mood", + searchPhrase: "", }; return ( @@ -35,7 +35,7 @@ export default async function UserVariablesPage() { - + ) } diff --git a/apps/nextjs/components/RemoteMdxLoader.tsx b/apps/nextjs/components/RemoteMdxLoader.tsx index 237ba5b6a..aad0dc512 100644 --- a/apps/nextjs/components/RemoteMdxLoader.tsx +++ b/apps/nextjs/components/RemoteMdxLoader.tsx @@ -1,15 +1,17 @@ "use client"; import { useEffect, useState } from 'react'; import { MDXRemote } from 'next-mdx-remote/rsc'; -import { siteConfig } from '@/config/site'; // Adjust the path as necessary +import { siteConfig } from '@/config/site'; +import {Icons} from "@/components/icons"; +import * as React from "react"; // Adjust the path as necessary const RemoteMdxLoader = ({ inputUrl }: { inputUrl: string }) => { const [mdxSource, setMdxSource] = useState(''); useEffect(() => { - const url = inputUrl.startsWith('http://') || inputUrl.startsWith('https://') ? + const url = inputUrl.startsWith('http://') || inputUrl.startsWith('https://') ? inputUrl : `${siteConfig.url.base}/${inputUrl}`; - + fetch(url) .then((res) => res.text()) // Assuming the endpoint returns MDX content directly .then((mdxContent) => { @@ -29,7 +31,11 @@ const RemoteMdxLoader = ({ inputUrl }: { inputUrl: string }) => { return (
- {mdxSource ? :

Loading...

} + {mdxSource ? : +
+ +
+ }
); }; diff --git a/apps/nextjs/components/userVariable/user-variable-list.tsx b/apps/nextjs/components/genericVariables/generic-variable-list.tsx similarity index 83% rename from apps/nextjs/components/userVariable/user-variable-list.tsx rename to apps/nextjs/components/genericVariables/generic-variable-list.tsx index 930f00793..00ad693ce 100644 --- a/apps/nextjs/components/userVariable/user-variable-list.tsx +++ b/apps/nextjs/components/genericVariables/generic-variable-list.tsx @@ -2,8 +2,8 @@ import { EmptyPlaceholder } from "@/components/empty-placeholder"; import { Icons } from "@/components/icons"; -import { UserVariableAddButton } from "./user-variable-add-button"; -import { UserVariableItem } from "./user-variable-item"; +import { UserVariableAddButton } from "../userVariables/user-variable-add-button"; +import { UserVariableItem } from "../userVariables/user-variable-item"; import { FC, useEffect, useState } from "react"; import { UserVariable } from "@/types/models/UserVariable"; @@ -20,9 +20,9 @@ type UserVariableListProps = { }; }; -export const UserVariableList: FC = ({ user, searchParams }) => { +export const GenericVariableList: FC = ({ user, searchParams }) => { - const [userVariables, setUserVariables] = useState([]); + const [genericVariables, setGenericVariables] = useState([]); const [isLoading, setIsLoading] = useState(true); useEffect(() => { @@ -44,7 +44,7 @@ export const UserVariableList: FC = ({ user, searchParams fetch(url) .then(response => response.json()) .then(userVariables => { - setUserVariables(userVariables); + setGenericVariables(userVariables); setIsLoading(false); }) .catch(error => { @@ -56,11 +56,11 @@ export const UserVariableList: FC = ({ user, searchParams return ( <> - {isLoading ? (
+ {isLoading ? (
) : "" } - {userVariables?.length ? ( + {genericVariables?.length ? (
{/* Add Tailwind classes here */} - {userVariables.map((userVariable) => ( + {genericVariables.map((userVariable) => ( ))}
diff --git a/apps/nextjs/components/userVariable/user-variable-search.tsx b/apps/nextjs/components/genericVariables/generic-variable-search.tsx similarity index 73% rename from apps/nextjs/components/userVariable/user-variable-search.tsx rename to apps/nextjs/components/genericVariables/generic-variable-search.tsx index 7a97ce549..a0b4fee1a 100644 --- a/apps/nextjs/components/userVariable/user-variable-search.tsx +++ b/apps/nextjs/components/genericVariables/generic-variable-search.tsx @@ -1,14 +1,16 @@ "use client"; import { FC, useEffect, useState } from "react"; -import {UserVariableList} from "@/components/userVariable/user-variable-list"; +import {GenericVariableList} from "@/components/genericVariables/generic-variable-list"; type UserVariableSearchProps = { user: { id: string; }; + includePublic?: boolean; // Optional parameter with a default value + sort?: string; // Optional parameter with a default value }; -export const UserVariableSearch: FC = ({ user }) => { +export const GenericVariableSearch: FC = ({ user, includePublic = true, sort = '-numberOfUserVariables' }) => { // State to manage search phrase const [searchPhrase, setSearchPhrase] = useState(""); @@ -16,8 +18,8 @@ export const UserVariableSearch: FC = ({ user }) => { // Define search parameters const searchParams = { - includePublic: true, - sort: '-numberOfUserVariables', + includePublic: includePublic, + sort: sort, limit: 10, offset: 0, searchPhrase: debouncedSearchPhrase, // Use debounced value @@ -43,7 +45,7 @@ export const UserVariableSearch: FC = ({ user }) => { className="input-class form-control block w-full px-3 py-1.5 text-base font-normal text-gray-700 bg-white bg-clip-padding border border-solid border-gray-300 rounded-full transition ease-in-out m-0 focus:text-gray-700 focus:bg-white focus:border-blue-600 focus:outline-none" />
- + ); }; diff --git a/apps/nextjs/components/userVariable/stats/stats-cards.tsx b/apps/nextjs/components/userVariables/stats/stats-cards.tsx similarity index 100% rename from apps/nextjs/components/userVariable/stats/stats-cards.tsx rename to apps/nextjs/components/userVariables/stats/stats-cards.tsx diff --git a/apps/nextjs/components/userVariable/user-variable-add-button.tsx b/apps/nextjs/components/userVariables/user-variable-add-button.tsx similarity index 100% rename from apps/nextjs/components/userVariable/user-variable-add-button.tsx rename to apps/nextjs/components/userVariables/user-variable-add-button.tsx diff --git a/apps/nextjs/components/userVariable/user-variable-charts.tsx b/apps/nextjs/components/userVariables/user-variable-charts.tsx similarity index 100% rename from apps/nextjs/components/userVariable/user-variable-charts.tsx rename to apps/nextjs/components/userVariables/user-variable-charts.tsx diff --git a/apps/nextjs/components/userVariable/user-variable-edit-form.tsx b/apps/nextjs/components/userVariables/user-variable-edit-form.tsx similarity index 100% rename from apps/nextjs/components/userVariable/user-variable-edit-form.tsx rename to apps/nextjs/components/userVariables/user-variable-edit-form.tsx diff --git a/apps/nextjs/components/userVariable/user-variable-item.tsx b/apps/nextjs/components/userVariables/user-variable-item.tsx similarity index 88% rename from apps/nextjs/components/userVariable/user-variable-item.tsx rename to apps/nextjs/components/userVariables/user-variable-item.tsx index aa654ebd5..d51d240ac 100644 --- a/apps/nextjs/components/userVariable/user-variable-item.tsx +++ b/apps/nextjs/components/userVariables/user-variable-item.tsx @@ -3,11 +3,12 @@ import Link from "next/link" import { Skeleton } from "@/components/ui/skeleton" -import { UserVariableOperationsButton } from "@/components/userVariable/user-variable-operations-button" -import { QuickMeasurementButton } from '@/components/userVariable/measurements/quick-measurement-button'; -import { MeasurementButton } from '@/components/userVariable/measurement-button'; +import { UserVariableOperationsButton } from "@/components/userVariables/user-variable-operations-button" +import { QuickMeasurementButton } from '@/components/measurements/quick-measurement-button'; +import { MeasurementButton } from '@/components/measurements/measurement-button'; import { UserVariable } from "@/types/models/UserVariable"; import { Icons } from "../icons"; +import {Button} from "@/components/ui/button"; interface UserVariableItemProps { userVariable: UserVariable; @@ -43,13 +44,13 @@ export function UserVariableItem({ userVariable }: UserVariableItemProps) {
diff --git a/apps/nextjs/components/userVariable/user-variable-overview.tsx b/apps/nextjs/components/userVariables/user-variable-overview.tsx similarity index 89% rename from apps/nextjs/components/userVariable/user-variable-overview.tsx rename to apps/nextjs/components/userVariables/user-variable-overview.tsx index 950bc5c5b..066f7eb4c 100644 --- a/apps/nextjs/components/userVariable/user-variable-overview.tsx +++ b/apps/nextjs/components/userVariables/user-variable-overview.tsx @@ -4,10 +4,11 @@ import { FC, useEffect, useState } from "react"; import { UserVariable } from "@/types/models/UserVariable"; import { DashboardHeader } from "@/components/pages/dashboard/dashboard-header"; import { DateRangePicker } from "@/components/date-range-picker"; -import { UserVariableOperationsButton } from "@/components/userVariable/user-variable-operations-button"; +import { UserVariableOperationsButton } from "@/components/userVariables/user-variable-operations-button"; import { cn } from "@/lib/utils"; import { buttonVariants } from "@/components/ui/button"; -import { MeasurementsList } from "@/components/userVariable/measurements/measurements-list"; +import { MeasurementsList } from "@/components/measurements/measurements-list"; +import * as React from "react"; type UserVariableOverviewProps = { user: { id: string; @@ -42,7 +43,9 @@ export const UserVariableOverview: FC = ({ user, vari }, [user, variableId]); if (isLoading) { - return
Loading...
; // Show a loader or a loading component + return
+ +
; } // Ensure userVariable is defined before trying to access its properties