feat: refactor class selection handling by introducing user store and updating related components

This commit is contained in:
Rémi 2025-01-06 00:31:25 +01:00
parent da74d1bf82
commit 1684ac2743
8 changed files with 65 additions and 32 deletions

View File

@ -1,5 +1,4 @@
"use client"; "use client";
import { useClassStore } from "@/app/stores/classStore";
import { User } from "@/app/types/next-auth"; import { User } from "@/app/types/next-auth";
import { getInitials } from "@/app/utils/initial"; import { getInitials } from "@/app/utils/initial";
import { import {
@ -19,19 +18,28 @@ import {
import { useRouter } from "next/navigation"; import { useRouter } from "next/navigation";
import { useEffect } from "react"; import { useEffect } from "react";
import { ThemeSwitcher } from "../ThemeSwitcher/ThemeSwitcher"; import { ThemeSwitcher } from "../ThemeSwitcher/ThemeSwitcher";
import { useUserStore } from "@/app/stores/userStore";
import { useClassStore } from "@/app/stores/classStore";
export const HeaderContent = ({ user }: { user?: User }) => { export const HeaderContent = ({ user }: { user?: User }) => {
const router = useRouter(); const router = useRouter();
const { classes, selectedClass, setSelectedClass, fetchClass } =
useClassStore();
const initials = user?.name ? getInitials(user.name) : ""; const { classes, fetchClass } = useClassStore();
const {
currentClassId: selectedClassId,
setCurrentClassId: setSelectedClassId,
} = useUserStore();
useEffect(() => { useEffect(() => {
fetchClass().then((classesFetched) => { fetchClass();
setSelectedClass(classesFetched[0]); }, [fetchClass]);
});
}, [fetchClass, setSelectedClass]); const selectedClass = classes.find((Class) => Class.id === selectedClassId);
useEffect(() => {
if (!selectedClass && classes.length > 0)
setSelectedClassId(classes[0].id);
}, [selectedClass, classes, setSelectedClassId]);
return ( return (
<Navbar className="mb-2"> <Navbar className="mb-2">
@ -46,15 +54,15 @@ export const HeaderContent = ({ user }: { user?: User }) => {
value={selectedClass?.name} value={selectedClass?.name}
selectedKey={selectedClass?.id} selectedKey={selectedClass?.id}
onSelectionChange={(selectedId) => { onSelectionChange={(selectedId) => {
console.log(selectedId);
const inputSelectedClass = classes.find( const inputSelectedClass = classes.find(
(Class) => Class.id === selectedId, (Class) => Class.id === selectedId,
); );
setSelectedClass(inputSelectedClass); if (inputSelectedClass)
setSelectedClassId(inputSelectedClass.id);
}} }}
> >
{classes.map((Class) => ( {classes.map((Class) => (
<AutocompleteItem key={Class.id} isSelected> <AutocompleteItem key={Class.id}>
{Class.name} {Class.name}
</AutocompleteItem> </AutocompleteItem>
))} ))}
@ -86,7 +94,7 @@ export const HeaderContent = ({ user }: { user?: User }) => {
as="button" as="button"
className="transition-transform" className="transition-transform"
color="secondary" color="secondary"
name={initials} name={user?.name ? getInitials(user.name) : ""}
size="sm" size="sm"
/> />
</DropdownTrigger> </DropdownTrigger>

View File

@ -1,16 +1,16 @@
"use client"; "use client";
import { useRoomStore } from "@/app/stores/roomStore"; import { useRoomStore } from "@/app/stores/roomStore";
import { useUserStore } from "@/app/stores/userStore";
import { useEffect } from "react"; import { useEffect } from "react";
import { RoomList } from "./List"; import { RoomList } from "./List";
import { useClassStore } from "@/app/stores/classStore";
export const RoomTable = () => { export const RoomTable = () => {
const { fetchRooms, actual, future, past } = useRoomStore(); const { fetchRooms, actual, future, past } = useRoomStore();
const { selectedClass } = useClassStore(); const { currentClassId: selectedClassId } = useUserStore();
useEffect(() => { useEffect(() => {
fetchRooms(); if (selectedClassId) fetchRooms();
}, [fetchRooms, selectedClass]); }, [fetchRooms, selectedClassId]);
return ( return (
<div className="flex flex-col gap-4"> <div className="flex flex-col gap-4">

View File

@ -10,7 +10,7 @@ export const Sidebar = () => {
const router = useRouter(); const router = useRouter();
return ( return (
<aside className="fixed top-0 left-0 w-64 h-screen transition-transform -translate-x-full sm:translate-x-0"> <aside className="fixed top-0 left-0 w-64 h-screen">
<div className="flex flex-col gap-2 h-full px-3 py-4 overflow-y-auto bg-foreground-100"> <div className="flex flex-col gap-2 h-full px-3 py-4 overflow-y-auto bg-foreground-100">
<ul className="font-medium gap-2"> <ul className="font-medium gap-2">
<li> <li>

View File

@ -1,6 +1,5 @@
import { API_URLS } from "../constants/apiUrl.constant"; import { API_URLS } from "../constants/apiUrl.constant";
import { axiosInstance } from "../lib/axios"; import { axiosInstance } from "../lib/axios";
import { Class } from "../stores/classStore";
const getAll = () => axiosInstance.get<Class[]>(API_URLS.class.all); const getAll = () => axiosInstance.get<Class[]>(API_URLS.class.all);

View File

@ -1,24 +1,19 @@
import { create } from "zustand"; import { create } from "zustand";
import { classService } from "../services/class.service"; import { classService } from "../services/class.service";
export type Class = { id: string; name: string; createdAt: string };
type ClassStoreState = { type ClassStoreState = {
classes: Class[]; classes: Class[];
selectedClass: Class | undefined | null;
}; };
type ClassStoreActions = { type ClassStoreActions = {
_setClass: (classes: Class[]) => void; _setClass: (classes: Class[]) => void;
fetchClass: () => Promise<Class[]>; fetchClass: () => Promise<Class[]>;
setSelectedClass: (selectedClass: Class | undefined | null) => void;
}; };
type ClassStore = ClassStoreState & ClassStoreActions; type ClassStore = ClassStoreState & ClassStoreActions;
const defaultState: ClassStoreState = { const defaultState: ClassStoreState = {
classes: [], classes: [],
selectedClass: null,
}; };
export const useClassStore = create<ClassStore>()((set) => ({ export const useClassStore = create<ClassStore>()((set) => ({
@ -28,11 +23,6 @@ export const useClassStore = create<ClassStore>()((set) => ({
classes: classes, classes: classes,
})); }));
}, },
setSelectedClass: (selectedClass: Class | undefined | null) => {
set(() => ({
selectedClass: selectedClass,
}));
},
fetchClass: async () => { fetchClass: async () => {
const classResponse = await classService.getAll(); const classResponse = await classService.getAll();
useClassStore.getState()._setClass(classResponse.data); useClassStore.getState()._setClass(classResponse.data);

View File

@ -2,7 +2,7 @@ import moment from "moment";
import { create } from "zustand"; import { create } from "zustand";
import { Room } from "../components/Room/Room"; import { Room } from "../components/Room/Room";
import { axiosInstance } from "../lib/axios"; import { axiosInstance } from "../lib/axios";
import { useClassStore } from "./classStore"; import { useUserStore } from "./userStore";
type RoomStoreState = { type RoomStoreState = {
future: Room[] | null; future: Room[] | null;
@ -38,11 +38,11 @@ export const useRoomStore = create<RoomStore>()((set) => ({
set({ future, actual, past }); set({ future, actual, past });
}, },
fetchRooms: () => { fetchRooms: () => {
const classSelected = useClassStore.getState().selectedClass; const selectedClassId = useUserStore.getState().currentClassId;
if (!classSelected) return; if (!selectedClassId) return;
axiosInstance axiosInstance
.get<Room[]>(`/@me/class/${classSelected.id}/rooms`) .get<Room[]>(`/@me/class/${selectedClassId}/rooms`)
.then((classes) => { .then((classes) => {
useRoomStore.getState()._setRooms(classes.data); useRoomStore.getState()._setRooms(classes.data);
}); });

View File

@ -0,0 +1,31 @@
import { create } from "zustand";
import { persist, createJSONStorage } from "zustand/middleware";
type UserStoreState = {
currentClassId: string | null;
};
type UserStoreActions = {
setCurrentClassId: (classId: string) => void;
};
type UserStore = UserStoreState & UserStoreActions;
const defaultState: UserStoreState = {
currentClassId: null,
};
export const useUserStore = create<UserStore>()(
persist(
(set) => ({
...defaultState,
setCurrentClassId: (classId: string) => {
set({ currentClassId: classId });
},
}),
{
name: "userStore",
storage: createJSONStorage(() => localStorage),
},
),
);

5
src/app/types/class.d.ts vendored Normal file
View File

@ -0,0 +1,5 @@
interface Class {
id: string;
name: string;
createdAt: string;
}