From 4f4b71bf6861ec6248784a51273ec4a450c4efee Mon Sep 17 00:00:00 2001 From: TkymHrt <23.h.takayama.nutfes@gmail.com> Date: Tue, 13 Jan 2026 00:16:24 +0900 Subject: [PATCH 1/9] refactor: update README and package files to use pnpm and add zustand dependency --- view/next-project/README.md | 4 +- view/next-project/package.json | 5 +-- view/next-project/pnpm-lock.yaml | 67 +++++++++++++------------------- 3 files changed, 31 insertions(+), 45 deletions(-) diff --git a/view/next-project/README.md b/view/next-project/README.md index c87e0421d..d263d759f 100644 --- a/view/next-project/README.md +++ b/view/next-project/README.md @@ -5,9 +5,7 @@ This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next First, run the development server: ```bash -npm run dev -# or -yarn dev +pnpm dev ``` Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. diff --git a/view/next-project/package.json b/view/next-project/package.json index 788cb0687..df408a99b 100644 --- a/view/next-project/package.json +++ b/view/next-project/package.json @@ -44,10 +44,9 @@ "react-pdf": "^9.2.1", "react-router-dom": "^6.0.2", "react-select": "^5.7.3", - "recoil": "^0.7.6", - "recoil-persist": "^4.2.0", "swr": "^2.3.0", - "tailwindcss": "^3.1.6" + "tailwindcss": "^3.1.6", + "zustand": "^5.0.10" }, "devDependencies": { "@chromatic-com/storybook": "^1.4.0", diff --git a/view/next-project/pnpm-lock.yaml b/view/next-project/pnpm-lock.yaml index 24f907ea1..7638a0858 100644 --- a/view/next-project/pnpm-lock.yaml +++ b/view/next-project/pnpm-lock.yaml @@ -95,18 +95,15 @@ importers: react-select: specifier: ^5.7.3 version: 5.10.2(@types/react@18.3.27)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - recoil: - specifier: ^0.7.6 - version: 0.7.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - recoil-persist: - specifier: ^4.2.0 - version: 4.2.0(recoil@0.7.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)) swr: specifier: ^2.3.0 version: 2.3.8(react@18.3.1) tailwindcss: specifier: ^3.1.6 version: 3.4.19(yaml@2.8.2) + zustand: + specifier: ^5.0.10 + version: 5.0.10(@types/react@18.3.27)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)) devDependencies: '@chromatic-com/storybook': specifier: ^1.4.0 @@ -3520,9 +3517,6 @@ packages: graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - hamt_plus@1.0.2: - resolution: {integrity: sha512-t2JXKaehnMb9paaYA7J0BX8QQAY8lwfQ9Gjf4pg/mk4krt+cmwmU652HOoWonf+7+EQV97ARPMhhVgU1ra2GhA==} - has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -4874,23 +4868,6 @@ packages: resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} engines: {node: '>= 4'} - recoil-persist@4.2.0: - resolution: {integrity: sha512-MHVfML9GxJP3RpkKR4F5rp7DtvzIvjWhowtMao/b7h2k4afMio/4sMAdUtltIrDaeVegH0Iga8Sx5XQ3oD7CzA==} - peerDependencies: - recoil: ^0.7.2 - - recoil@0.7.7: - resolution: {integrity: sha512-8Og5KPQW9LwC577Vc7Ug2P0vQshkv1y3zG3tSSkWMqkWSwHmE+by06L8JtnGocjW6gcCvfwB3YtrJG6/tWivNQ==} - peerDependencies: - react: '>=16.13.1' - react-dom: '*' - react-native: '*' - peerDependenciesMeta: - react-dom: - optional: true - react-native: - optional: true - redent@3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} @@ -5822,6 +5799,24 @@ packages: yoga-layout@2.0.1: resolution: {integrity: sha512-tT/oChyDXelLo2A+UVnlW9GU7CsvFMaEnd9kVFsaiCQonFAXd3xrHhkLYu+suwwosrAEQ746xBU+HvYtm1Zs2Q==} + zustand@5.0.10: + resolution: {integrity: sha512-U1AiltS1O9hSy3rul+Ub82ut2fqIAefiSuwECWt6jlMVUGejvf+5omLcRBSzqbRagSM3hQZbtzdeRc6QVScXTg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + snapshots: '@adobe/css-tools@4.4.4': {} @@ -10023,8 +10018,6 @@ snapshots: graphemer@1.4.0: {} - hamt_plus@1.0.2: {} - has-bigints@1.1.0: {} has-flag@4.0.0: {} @@ -11446,17 +11439,6 @@ snapshots: tiny-invariant: 1.3.3 tslib: 2.8.1 - recoil-persist@4.2.0(recoil@0.7.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1)): - dependencies: - recoil: 0.7.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - - recoil@0.7.7(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - hamt_plus: 1.0.2 - react: 18.3.1 - optionalDependencies: - react-dom: 18.3.1(react@18.3.1) - redent@3.0.0: dependencies: indent-string: 4.0.0 @@ -12520,3 +12502,10 @@ snapshots: yocto-queue@1.2.2: {} yoga-layout@2.0.1: {} + + zustand@5.0.10(@types/react@18.3.27)(immer@9.0.21)(react@18.3.1)(use-sync-external-store@1.6.0(react@18.3.1)): + optionalDependencies: + '@types/react': 18.3.27 + immer: 9.0.21 + react: 18.3.1 + use-sync-external-store: 1.6.0(react@18.3.1) From 8f75479abf688b5ca0262d92f815c8caf81b2fc9 Mon Sep 17 00:00:00 2001 From: TkymHrt <23.h.takayama.nutfes@gmail.com> Date: Tue, 13 Jan 2026 00:17:04 +0900 Subject: [PATCH 2/9] refactor: migrate state management from Recoil to Zustand --- view/next-project/src/pages/_app.tsx | 27 +++++------- view/next-project/src/store/atoms/AuthAtom.ts | 15 ------- view/next-project/src/store/atoms/UserAtom.ts | 20 --------- view/next-project/src/store/atoms/index.ts | 4 -- view/next-project/src/store/authStore.ts | 39 ++++++++++++++++ view/next-project/src/store/index.ts | 2 + view/next-project/src/store/storeKeys.ts | 4 -- view/next-project/src/store/userStore.ts | 44 +++++++++++++++++++ 8 files changed, 97 insertions(+), 58 deletions(-) delete mode 100644 view/next-project/src/store/atoms/AuthAtom.ts delete mode 100644 view/next-project/src/store/atoms/UserAtom.ts delete mode 100644 view/next-project/src/store/atoms/index.ts create mode 100644 view/next-project/src/store/authStore.ts create mode 100644 view/next-project/src/store/index.ts delete mode 100644 view/next-project/src/store/storeKeys.ts create mode 100644 view/next-project/src/store/userStore.ts diff --git a/view/next-project/src/pages/_app.tsx b/view/next-project/src/pages/_app.tsx index e66754adc..d74c92c55 100644 --- a/view/next-project/src/pages/_app.tsx +++ b/view/next-project/src/pages/_app.tsx @@ -2,7 +2,6 @@ import { ChakraProvider } from '@chakra-ui/react'; import localFont from 'next/font/local'; import Head from 'next/head'; import { NuqsAdapter } from 'nuqs/adapters/next/pages'; -import { RecoilRoot } from 'recoil'; import Layout from '@components/layout/Layout'; import { ManagedUIContext } from '@components/ui/context'; @@ -18,20 +17,18 @@ export const notoSansJP = localFont({ function MyApp({ Component, pageProps }: AppProps) { return ( - - - - - - - - - - - - - - + + + + + + + + + + + + ); } diff --git a/view/next-project/src/store/atoms/AuthAtom.ts b/view/next-project/src/store/atoms/AuthAtom.ts deleted file mode 100644 index 6585db420..000000000 --- a/view/next-project/src/store/atoms/AuthAtom.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { atom } from 'recoil'; -import { recoilPersist } from 'recoil-persist'; - -import { STORE_KEYS } from '@/store/storeKeys'; - -const { persistAtom } = recoilPersist(); - -export const authAtom = atom({ - key: STORE_KEYS.AUTH_STATE, - default: { - isSignIn: false, - accessToken: '', - }, - effects_UNSTABLE: [persistAtom], -}); diff --git a/view/next-project/src/store/atoms/UserAtom.ts b/view/next-project/src/store/atoms/UserAtom.ts deleted file mode 100644 index 4199c1ba8..000000000 --- a/view/next-project/src/store/atoms/UserAtom.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { atom } from 'recoil'; -import { recoilPersist } from 'recoil-persist'; - -import { STORE_KEYS } from '@/store/storeKeys'; -import { User } from '@/type/common'; - -const { persistAtom } = recoilPersist(); - -export const userAtom = atom({ - key: STORE_KEYS.USER_STATE, - default: { - id: 0, - name: '', - bureauID: 0, - roleID: 0, - createdAt: '', - updatedAt: '', - }, - effects_UNSTABLE: [persistAtom], -}); diff --git a/view/next-project/src/store/atoms/index.ts b/view/next-project/src/store/atoms/index.ts deleted file mode 100644 index 1b5ce0d2c..000000000 --- a/view/next-project/src/store/atoms/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { authAtom } from './AuthAtom'; -import { userAtom } from './UserAtom'; - -export { authAtom, userAtom }; diff --git a/view/next-project/src/store/authStore.ts b/view/next-project/src/store/authStore.ts new file mode 100644 index 000000000..cc6f04e4e --- /dev/null +++ b/view/next-project/src/store/authStore.ts @@ -0,0 +1,39 @@ +import { create } from 'zustand'; +import { createJSONStorage, persist } from 'zustand/middleware'; + +interface AuthState { + isSignIn: boolean; + accessToken: string; + _hasHydrated: boolean; +} + +interface AuthActions { + setAuth: (auth: Pick) => void; + resetAuth: () => void; + setHasHydrated: (state: boolean) => void; +} + +const initialState: Pick = { + isSignIn: false, + accessToken: '', +}; + +export const useAuthStore = create()( + persist( + (set) => ({ + ...initialState, + _hasHydrated: false, + setAuth: (auth) => set(auth), + resetAuth: () => set(initialState), + setHasHydrated: (state) => set({ _hasHydrated: state }), + }), + { + name: 'auth-storage', + storage: createJSONStorage(() => localStorage), + partialize: (state) => ({ isSignIn: state.isSignIn, accessToken: state.accessToken }), + onRehydrateStorage: () => (state) => { + state?.setHasHydrated(true); + }, + }, + ), +); diff --git a/view/next-project/src/store/index.ts b/view/next-project/src/store/index.ts new file mode 100644 index 000000000..5007e1770 --- /dev/null +++ b/view/next-project/src/store/index.ts @@ -0,0 +1,2 @@ +export { useAuthStore } from './authStore'; +export { useUserStore } from './userStore'; diff --git a/view/next-project/src/store/storeKeys.ts b/view/next-project/src/store/storeKeys.ts deleted file mode 100644 index 66f21473c..000000000 --- a/view/next-project/src/store/storeKeys.ts +++ /dev/null @@ -1,4 +0,0 @@ -export const STORE_KEYS = { - AUTH_STATE: 'authAtom', - USER_STATE: 'userAtom', -} as const; diff --git a/view/next-project/src/store/userStore.ts b/view/next-project/src/store/userStore.ts new file mode 100644 index 000000000..23911e2cb --- /dev/null +++ b/view/next-project/src/store/userStore.ts @@ -0,0 +1,44 @@ +import { create } from 'zustand'; +import { createJSONStorage, persist } from 'zustand/middleware'; + +import { User } from '@/type/common'; + +interface UserState { + user: User; + _hasHydrated: boolean; +} + +interface UserActions { + setUser: (user: User) => void; + resetUser: () => void; + setHasHydrated: (state: boolean) => void; +} + +const initialUser: User = { + id: 0, + name: '', + bureauID: 0, + roleID: 0, + createdAt: '', + updatedAt: '', +}; + +export const useUserStore = create()( + persist( + (set) => ({ + user: initialUser, + _hasHydrated: false, + setUser: (user) => set({ user }), + resetUser: () => set({ user: initialUser }), + setHasHydrated: (state) => set({ _hasHydrated: state }), + }), + { + name: 'user-storage', + storage: createJSONStorage(() => localStorage), + partialize: (state) => ({ user: state.user }), + onRehydrateStorage: () => (state) => { + state?.setHasHydrated(true); + }, + }, + ), +); From ec8f586dc7a00a34e12d15a6d5cb2e3dc0c4a8b1 Mon Sep 17 00:00:00 2001 From: TkymHrt <23.h.takayama.nutfes@gmail.com> Date: Tue, 13 Jan 2026 00:31:49 +0900 Subject: [PATCH 3/9] refactor: migrate state management from Recoil to Zustand in auth components --- .../src/components/auth/SignInView.tsx | 7 +- .../src/components/auth/SignUpView.tsx | 7 +- .../src/components/common/Header/Header.tsx | 12 +-- .../layout/MainLayout/MainLayout.tsx | 99 ++++++++++++------- 4 files changed, 76 insertions(+), 49 deletions(-) diff --git a/view/next-project/src/components/auth/SignInView.tsx b/view/next-project/src/components/auth/SignInView.tsx index b6c6d249b..775a509d0 100644 --- a/view/next-project/src/components/auth/SignInView.tsx +++ b/view/next-project/src/components/auth/SignInView.tsx @@ -1,9 +1,8 @@ import Router from 'next/router'; import { useState } from 'react'; import { useForm } from 'react-hook-form'; -import { useRecoilState } from 'recoil'; -import { authAtom, userAtom } from '@/store/atoms'; +import { useAuthStore, useUserStore } from '@/store'; import { get_with_token } from '@api/api_methods'; import { signIn } from '@api/signIn'; import LoadingButton from '@components/common/LoadingButton'; @@ -14,8 +13,8 @@ import { PrimaryButton } from '../common'; export default function SignInView() { // ログイン中フラグ const [isSignInNow, setIsSignInNow] = useState(false); - const [, setAuth] = useRecoilState(authAtom); - const [, setUser] = useRecoilState(userAtom); + const setAuth = useAuthStore((state) => state.setAuth); + const setUser = useUserStore((state) => state.setUser); const { register, diff --git a/view/next-project/src/components/auth/SignUpView.tsx b/view/next-project/src/components/auth/SignUpView.tsx index 8e6858050..f599080da 100644 --- a/view/next-project/src/components/auth/SignUpView.tsx +++ b/view/next-project/src/components/auth/SignUpView.tsx @@ -1,10 +1,9 @@ import Router from 'next/router'; import React, { useState } from 'react'; import { useForm } from 'react-hook-form'; -import { useRecoilState } from 'recoil'; import { BUREAUS } from '@/constants/bureaus'; -import { authAtom, userAtom } from '@/store/atoms'; +import { useAuthStore, useUserStore } from '@/store'; import { get } from '@api/api_methods'; import { signUp } from '@api/signUp'; import { post } from '@api/user'; @@ -14,8 +13,8 @@ import { SignUp, User } from '@type/common'; import { PrimaryButton } from '../common'; export default function SignUpView() { - const [, setAuth] = useRecoilState(authAtom); - const [, setUser] = useRecoilState(userAtom); + const setAuth = useAuthStore((state) => state.setAuth); + const setUser = useUserStore((state) => state.setUser); // 新規登録中フラグ const [isSignUpNow, setIsSignUpNow] = useState(false); diff --git a/view/next-project/src/components/common/Header/Header.tsx b/view/next-project/src/components/common/Header/Header.tsx index 0d0f9f31a..45fe66975 100644 --- a/view/next-project/src/components/common/Header/Header.tsx +++ b/view/next-project/src/components/common/Header/Header.tsx @@ -2,30 +2,28 @@ import Image from 'next/image'; import Router from 'next/router'; import { AiOutlineMenu } from 'react-icons/ai'; import { RiAccountCircleFill } from 'react-icons/ri'; -import { useRecoilState } from 'recoil'; -import { authAtom, userAtom } from '@/store/atoms'; +import { useAuthStore, useUserStore } from '@/store'; import { del } from '@api/signOut'; import { ChakraUIDropdown } from '@components/common'; -import { User } from '@type/common'; import { HeaderProps } from './Header.type'; const Header = (props: HeaderProps) => { const { onSideNavOpen } = props; - const [auth, setAuth] = useRecoilState(authAtom); - const [user, setUser] = useRecoilState(userAtom); + const { accessToken, setAuth } = useAuthStore(); + const { user, resetUser } = useUserStore(); const signOut = async () => { const signOutUrl: string = process.env.CSR_API_URI + '/mail_auth/signout'; - const req = await del(signOutUrl, auth.accessToken); + const req = await del(signOutUrl, accessToken); const authData = { isSignIn: false, accessToken: '', }; if (req.status === 200) { setAuth(authData); - setUser({} as User); + resetUser(); Router.push('/'); } }; diff --git a/view/next-project/src/components/layout/MainLayout/MainLayout.tsx b/view/next-project/src/components/layout/MainLayout/MainLayout.tsx index e74ebddd8..811c32a9d 100644 --- a/view/next-project/src/components/layout/MainLayout/MainLayout.tsx +++ b/view/next-project/src/components/layout/MainLayout/MainLayout.tsx @@ -2,13 +2,11 @@ import clsx from 'clsx'; import Head from 'next/head'; import { useRouter } from 'next/router'; import React, { useEffect, useState } from 'react'; -import { useRecoilState } from 'recoil'; -import { authAtom, userAtom } from '@/store/atoms'; -import 'tailwindcss/tailwind.css'; -import { Header, SideNav } from '@components/common'; -import { User } from '@type/common'; +import { useAuthStore, useUserStore } from '@/store'; +import { Header, Loading, SideNav } from '@components/common'; import { get_with_token_valid } from '@utils/api/api_methods'; +import 'tailwindcss/tailwind.css'; import s from './MainLayout.module.css'; @@ -18,34 +16,57 @@ interface LayoutProps { export default function MainLayout(props: LayoutProps) { const router = useRouter(); - const [auth, setAuth] = useRecoilState(authAtom); - const [_, setUser] = useRecoilState(userAtom); + const { isSignIn, accessToken, resetAuth, _hasHydrated: authHasHydrated } = useAuthStore(); + const { resetUser, _hasHydrated: userHasHydrated } = useUserStore(); const [isSideNavOpen, setIsSideNavOpen] = useState(true); + const [isChecking, setIsChecking] = useState(true); + + const hasHydrated = authHasHydrated && userHasHydrated; + useEffect(() => { - const getCurrentUserUrl = process.env.CSR_API_URI + '/current_user'; - get_with_token_valid(getCurrentUserUrl, auth.accessToken).then((result) => { - if (!result) { - localStorage.clear(); - const authData = { - isSignIn: false, - accessToken: '', - }; - setAuth(authData); - setUser({} as User); - router.push('/'); + if (!hasHydrated) return; + + const validateSession = async () => { + if (!isSignIn || !accessToken) { + await handleLogout(); + return; + } + + const getCurrentUserUrl = process.env.CSR_API_URI + '/current_user'; + const isValid = await get_with_token_valid(getCurrentUserUrl, accessToken); + + if (!isValid) { + await handleLogout(); } else { - if (router.isReady) { - if (!auth.isSignIn) { - router.push('/'); - localStorage.clear(); - } else if (auth.isSignIn === true && router.pathname == '/') { - router.push('/purchaseorders'); - } + if (router.pathname === '/') { + await router.push('/my_page'); } + setIsChecking(false); } - }); - }, [router]); + }; + + const handleLogout = async () => { + resetAuth(); + resetUser(); + + if (router.pathname !== '/') { + await router.push('/'); + } + setIsChecking(false); + }; + + validateSession(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [hasHydrated, router.pathname]); + + if (!hasHydrated || isChecking) { + return ( +
+ +
+ ); + } return ( <> @@ -56,19 +77,29 @@ export default function MainLayout(props: LayoutProps) {
-
setIsSideNavOpen(!isSideNavOpen)} /> + {router.pathname !== '/' && ( +
setIsSideNavOpen(!isSideNavOpen)} /> + )}
+ {router.pathname !== '/' && ( +
+ +
+ )}
- -
-
{props.children}
From 61acb7ff4aaa1599e9216db5fd4c5afed034c382 Mon Sep 17 00:00:00 2001 From: TkymHrt <23.h.takayama.nutfes@gmail.com> Date: Tue, 13 Jan 2026 00:32:49 +0900 Subject: [PATCH 4/9] refactor: migrate state management from Recoil to Zustand across multiple components --- .../src/components/common/ChakraUIDropdown.tsx | 5 ++--- .../create_purchase_report/usePurchaseReportForm.ts | 9 ++++----- .../src/components/purchasereports/DetailPage1.tsx | 7 +++---- .../src/components/purchasereports/EditModal.tsx | 5 ++--- .../purchasereports/PurchaseReportAddModal.tsx | 5 ++--- .../purchasereports/PurchaseReportItemNumModal.tsx | 9 ++++----- .../next-project/src/components/yearperiods/AddModal.tsx | 7 +++---- view/next-project/src/pages/budget_managements/index.tsx | 5 ++--- view/next-project/src/pages/fund_informations/index.tsx | 7 +++---- view/next-project/src/pages/my_page/index.tsx | 5 ++--- .../src/pages/purchase_report_list/index.tsx | 9 ++++----- view/next-project/src/pages/teachers/index.tsx | 7 +++---- view/next-project/src/pages/users/index.tsx | 7 +++---- view/next-project/src/pages/yearperiods/index.tsx | 9 ++++----- 14 files changed, 41 insertions(+), 55 deletions(-) diff --git a/view/next-project/src/components/common/ChakraUIDropdown.tsx b/view/next-project/src/components/common/ChakraUIDropdown.tsx index 089ca9f22..4357225f0 100644 --- a/view/next-project/src/components/common/ChakraUIDropdown.tsx +++ b/view/next-project/src/components/common/ChakraUIDropdown.tsx @@ -1,9 +1,8 @@ import { Button, Menu, MenuButton, MenuItem, MenuList } from '@chakra-ui/react'; import React from 'react'; import { RiArrowDropDownLine } from 'react-icons/ri'; -import { useRecoilValue } from 'recoil'; -import { userAtom } from '@/store/atoms'; +import { useUserStore } from '@/store'; interface Props { title: string; @@ -12,7 +11,7 @@ interface Props { } const Dropdown = (props: Props) => { - const user = useRecoilValue(userAtom); + const user = useUserStore((state) => state.user); return ( diff --git a/view/next-project/src/components/create_purchase_report/usePurchaseReportForm.ts b/view/next-project/src/components/create_purchase_report/usePurchaseReportForm.ts index 06c71aff7..cd4637c71 100644 --- a/view/next-project/src/components/create_purchase_report/usePurchaseReportForm.ts +++ b/view/next-project/src/components/create_purchase_report/usePurchaseReportForm.ts @@ -1,16 +1,15 @@ import { NextRouter } from 'next/router'; -import { useState, useEffect } from 'react'; -import { useRecoilValue } from 'recoil'; +import { useEffect, useState } from 'react'; import { + useGetBuyReportsId, useGetDivisionsUsers, useGetFestivalItemsUsers, - useGetBuyReportsId, usePostBuyReports, usePutBuyReportsId, } from '@/generated/hooks'; import { DivisionOption, FestivalItemOption } from '@/generated/model'; -import { userAtom } from '@/store/atoms'; +import { useUserStore } from '@/store'; import type { BuyReport, PostBuyReportsBody, PutBuyReportsIdBody } from '@/generated/model'; @@ -49,7 +48,7 @@ export const usePurchaseReportForm = (router: NextRouter) => { const reportId = reportIdParam ? Number(reportIdParam) : undefined; const isEditMode = from === 'purchase_report_list'; - const user = useRecoilValue(userAtom); + const user = useUserStore((state) => state.user); const [departments, setDepartments] = useState([]); const [uploadedFile, setUploadedFile] = useState(null); const [festivalItems, setFestivalItems] = useState([]); diff --git a/view/next-project/src/components/purchasereports/DetailPage1.tsx b/view/next-project/src/components/purchasereports/DetailPage1.tsx index 1165ce133..be7aab1c0 100644 --- a/view/next-project/src/components/purchasereports/DetailPage1.tsx +++ b/view/next-project/src/components/purchasereports/DetailPage1.tsx @@ -2,14 +2,13 @@ import { useRouter } from 'next/router'; import React, { FC, useEffect, useMemo, useState } from 'react'; import { FaChevronCircleRight } from 'react-icons/fa'; import { RiExternalLinkLine, RiFileCopyLine } from 'react-icons/ri'; -import { useRecoilState } from 'recoil'; import PrimaryButton from '@/components/common/OutlinePrimaryButton/OutlinePrimaryButton'; -import { userAtom } from '@/store/atoms'; +import { useUserStore } from '@/store'; import { downloadFile } from '@/utils/downloadFile'; import { del } from '@api/api_methods'; import { Checkbox, RedButton, Tooltip } from '@components/common'; -import { PurchaseItem, PurchaseReport, PurchaseReportView, Expense } from '@type/common'; +import { Expense, PurchaseItem, PurchaseReport, PurchaseReportView } from '@type/common'; import { createPurchaseReportFormPdf } from '@utils/createPurchaseReportPdf'; interface DetailModalProps { @@ -22,7 +21,7 @@ interface DetailModalProps { } const DetailPage1: FC = (props) => { - const [user] = useRecoilState(userAtom); + const user = useUserStore((state) => state.user); const [date, setDate] = useState(String); const [japaneseDate, setJapaneseDate] = useState(String); diff --git a/view/next-project/src/components/purchasereports/EditModal.tsx b/view/next-project/src/components/purchasereports/EditModal.tsx index 7ba9f9016..e0b6c80ff 100644 --- a/view/next-project/src/components/purchasereports/EditModal.tsx +++ b/view/next-project/src/components/purchasereports/EditModal.tsx @@ -1,9 +1,8 @@ import { useRouter } from 'next/router'; import React, { useCallback, useEffect, useState } from 'react'; import { RiArrowDropRightLine } from 'react-icons/ri'; -import { useRecoilState } from 'recoil'; -import { userAtom } from '@/store/atoms'; +import { useUserStore } from '@/store'; import { get, put as putPurchaseReport } from '@api/api_methods'; import { put as putPurchaseItem } from '@api/purchaseItem'; import { @@ -26,7 +25,7 @@ interface ModalProps { } export default function EditModal(props: ModalProps) { - const [user] = useRecoilState(userAtom); + const user = useUserStore((state) => state.user); const router = useRouter(); diff --git a/view/next-project/src/components/purchasereports/PurchaseReportAddModal.tsx b/view/next-project/src/components/purchasereports/PurchaseReportAddModal.tsx index 44368b657..a0e65eeb0 100644 --- a/view/next-project/src/components/purchasereports/PurchaseReportAddModal.tsx +++ b/view/next-project/src/components/purchasereports/PurchaseReportAddModal.tsx @@ -1,9 +1,8 @@ import { useRouter } from 'next/router'; import React, { useCallback, useEffect, useState } from 'react'; import { RiArrowDropRightLine } from 'react-icons/ri'; -import { useRecoilState } from 'recoil'; -import { userAtom } from '@/store/atoms'; +import { useUserStore } from '@/store'; import { get, post } from '@api/api_methods'; import { post as postItem, put } from '@api/purchaseItem'; import { post as postOrder } from '@api/purchaseOrder'; @@ -36,7 +35,7 @@ interface ModalProps { } export default function PurchaseReportAddModal(props: ModalProps) { - const [user] = useRecoilState(userAtom); + const user = useUserStore((state) => state.user); const router = useRouter(); diff --git a/view/next-project/src/components/purchasereports/PurchaseReportItemNumModal.tsx b/view/next-project/src/components/purchasereports/PurchaseReportItemNumModal.tsx index f06743da4..bf206485d 100644 --- a/view/next-project/src/components/purchasereports/PurchaseReportItemNumModal.tsx +++ b/view/next-project/src/components/purchasereports/PurchaseReportItemNumModal.tsx @@ -1,7 +1,6 @@ -import React, { useState, useEffect } from 'react'; -import { useRecoilState } from 'recoil'; +import React, { useEffect, useState } from 'react'; -import { userAtom } from '@/store/atoms'; +import { useUserStore } from '@/store'; import { CloseButton, Modal, @@ -12,7 +11,7 @@ import { } from '@components/common'; import PurchaseReportAddModal from '@components/purchasereports/PurchaseReportAddModal'; import { useUI } from '@components/ui/context'; -import { PurchaseOrder, Expense, YearPeriod } from '@type/common'; +import { Expense, PurchaseOrder, YearPeriod } from '@type/common'; import { get } from '@utils/api/api_methods'; export default function PurchaseReportItemNumModal() { @@ -30,7 +29,7 @@ export default function PurchaseReportItemNumModal() { getPeriods(); }, []); - const [user] = useRecoilState(userAtom); + const user = useUserStore((state) => state.user); const [expenses, setExpenses] = useState([]); const [expenseID, setExpenseID] = useState(0); diff --git a/view/next-project/src/components/yearperiods/AddModal.tsx b/view/next-project/src/components/yearperiods/AddModal.tsx index d5c7cb58a..c6dae373a 100644 --- a/view/next-project/src/components/yearperiods/AddModal.tsx +++ b/view/next-project/src/components/yearperiods/AddModal.tsx @@ -1,13 +1,12 @@ import { format } from 'date-fns'; import { useRouter } from 'next/router'; import React, { Dispatch, FC, SetStateAction, useState } from 'react'; -import { useRecoilState } from 'recoil'; -import { userAtom } from '@/store/atoms'; +import { useUserStore } from '@/store'; import { YearPeriod } from '@/type/common'; import { post } from '@/utils/api/api_methods'; -import { Modal, CloseButton, Input, PrimaryButton } from '../common'; +import { CloseButton, Input, Modal, PrimaryButton } from '../common'; interface ModalProps { setShowModal: Dispatch>; @@ -15,7 +14,7 @@ interface ModalProps { } const OpenAddModal: FC = (props) => { - const [user] = useRecoilState(userAtom); + const user = useUserStore((state) => state.user); const [flashMessage, setFlashMessage] = useState(''); const router = useRouter(); diff --git a/view/next-project/src/pages/budget_managements/index.tsx b/view/next-project/src/pages/budget_managements/index.tsx index bb3ce48f1..1b411c810 100644 --- a/view/next-project/src/pages/budget_managements/index.tsx +++ b/view/next-project/src/pages/budget_managements/index.tsx @@ -1,9 +1,8 @@ import router from 'next/router'; -import { useRecoilValue } from 'recoil'; import BudgetManagement from '@/components/budget_managements/BudgetManagement'; import MainLayout from '@/components/layout/MainLayout'; -import { userAtom } from '@/store/atoms'; +import { useUserStore } from '@/store'; import { Year } from '@/type/common'; import { get } from '@/utils/api/api_methods'; @@ -22,7 +21,7 @@ export async function getServerSideProps() { } export default function Home(props: Props) { - const user = useRecoilValue(userAtom); + const user = useUserStore((state) => state.user); user?.roleID === 1 && router.push('/my_page'); return ( diff --git a/view/next-project/src/pages/fund_informations/index.tsx b/view/next-project/src/pages/fund_informations/index.tsx index cfbeb7aac..50039c4a0 100644 --- a/view/next-project/src/pages/fund_informations/index.tsx +++ b/view/next-project/src/pages/fund_informations/index.tsx @@ -1,15 +1,14 @@ import Head from 'next/head'; import router from 'next/router'; -import { useRecoilValue } from 'recoil'; -import { FundInformationTable, FundInformationHeader } from '@/components/fund_information'; +import { FundInformationHeader, FundInformationTable } from '@/components/fund_information'; import { useFundInformations } from '@/components/fund_information/useFundInformations'; -import { userAtom } from '@/store/atoms'; +import { useUserStore } from '@/store'; import { Card } from '@components/common'; import MainLayout from '@components/layout/MainLayout'; export default function FundInformations() { - const user = useRecoilValue(userAtom); + const user = useUserStore((state) => state.user); user?.roleID === 1 && router.push('/my_page'); diff --git a/view/next-project/src/pages/my_page/index.tsx b/view/next-project/src/pages/my_page/index.tsx index 1f8f36c41..3257b6386 100644 --- a/view/next-project/src/pages/my_page/index.tsx +++ b/view/next-project/src/pages/my_page/index.tsx @@ -1,20 +1,19 @@ import { useRouter } from 'next/router'; import { useEffect, useState } from 'react'; import { RiAddCircleLine } from 'react-icons/ri'; -import { useRecoilValue } from 'recoil'; import { Card, Loading, PrimaryButton } from '@/components/common'; import MainLayout from '@/components/layout/MainLayout'; import TableSection from '@/components/mypage/TableSection'; import { useGetFestivalItemsDetailsUserId } from '@/generated/hooks'; -import { userAtom } from '@/store/atoms'; +import { useUserStore } from '@/store'; import { User } from '@/type/common'; import { notoSansJP } from '../_app'; const MyPage = () => { const router = useRouter(); - const user = useRecoilValue(userAtom); + const user = useUserStore((state) => state.user); const [currentUser, setCurrentUser] = useState(); useEffect(() => { diff --git a/view/next-project/src/pages/purchase_report_list/index.tsx b/view/next-project/src/pages/purchase_report_list/index.tsx index e583e3e1c..aa528a190 100644 --- a/view/next-project/src/pages/purchase_report_list/index.tsx +++ b/view/next-project/src/pages/purchase_report_list/index.tsx @@ -1,8 +1,7 @@ import { saveAs } from 'file-saver'; import { useRouter } from 'next/router'; -import { useCallback, useState, useEffect, useMemo } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { TbDownload } from 'react-icons/tb'; -import { useRecoilValue } from 'recoil'; import DownloadButton from '@/components/common/DownloadButton'; import PrimaryButton from '@/components/common/OutlinePrimaryButton/OutlinePrimaryButton'; @@ -12,14 +11,14 @@ import { useGetYearsPeriods, usePutBuyReportStatusBuyReportId, } from '@/generated/hooks'; -import { userAtom } from '@/store/atoms'; +import { useUserStore } from '@/store'; import { Card, Checkbox, EditButton, Loading, Title } from '@components/common'; import MainLayout from '@components/layout/MainLayout'; import OpenDeleteModalButton from '@components/purchasereports/OpenDeleteModalButton'; import type { - GetBuyReportsDetailsParams, BuyReportDetail, + GetBuyReportsDetailsParams, PutBuyReportStatusBuyReportIdBody, } from '@/generated/model'; @@ -31,7 +30,7 @@ export default function PurchaseReports() { error: yearPeriodsError, } = useGetYearsPeriods(); const yearPeriods = yearPeriodsData?.data; - const user = useRecoilValue(userAtom); + const user = useUserStore((state) => state.user); user?.roleID === 1 && router.push('/my_page'); diff --git a/view/next-project/src/pages/teachers/index.tsx b/view/next-project/src/pages/teachers/index.tsx index 19e391f2d..4c0afc2ec 100644 --- a/view/next-project/src/pages/teachers/index.tsx +++ b/view/next-project/src/pages/teachers/index.tsx @@ -1,9 +1,8 @@ import clsx from 'clsx'; import Head from 'next/head'; -import { useState, useEffect } from 'react'; -import { useRecoilValue } from 'recoil'; +import { useEffect, useState } from 'react'; -import { userAtom } from '@/store/atoms'; +import { useUserStore } from '@/store'; import { get } from '@api/api_methods'; import { Card, Title } from '@components/common'; import MainLayout from '@components/layout/MainLayout'; @@ -42,7 +41,7 @@ export default function TeachersList(props: Props) { departments[0], ); - const user = useRecoilValue(userAtom); + const user = useUserStore((state) => state.user); const [currentUser, setCurrentUser] = useState(); const isDisabled = !( currentUser?.roleID === 2 || diff --git a/view/next-project/src/pages/users/index.tsx b/view/next-project/src/pages/users/index.tsx index 7a1fdcf85..50a541c17 100644 --- a/view/next-project/src/pages/users/index.tsx +++ b/view/next-project/src/pages/users/index.tsx @@ -1,11 +1,10 @@ import clsx from 'clsx'; import Head from 'next/head'; import { useRouter } from 'next/router'; -import { useEffect, useState, useMemo } from 'react'; -import { useRecoilValue } from 'recoil'; +import { useEffect, useMemo, useState } from 'react'; import OpenDeleteModalButton from '@/components/users/OpenDeleteModalButton'; -import { userAtom } from '@/store/atoms'; +import { useUserStore } from '@/store'; import { get } from '@api/api_methods'; import { Card, Title } from '@components/common'; import MainLayout from '@components/layout/MainLayout/MainLayout'; @@ -36,7 +35,7 @@ export default function Users(props: Props) { const { users, bureaus } = props; const router = useRouter(); - const user = useRecoilValue(userAtom); + const user = useUserStore((state) => state.user); const [currentUser, setCurrentUser] = useState(); const [selectedBureau, setSelectedBureau] = useState(0); const [filterUsers, setFilterUsers] = useState(users); diff --git a/view/next-project/src/pages/yearperiods/index.tsx b/view/next-project/src/pages/yearperiods/index.tsx index f676fc47f..359820581 100644 --- a/view/next-project/src/pages/yearperiods/index.tsx +++ b/view/next-project/src/pages/yearperiods/index.tsx @@ -1,17 +1,16 @@ import clsx from 'clsx'; import Head from 'next/head'; import { useRouter } from 'next/router'; -import { useEffect, useState, useMemo } from 'react'; -import { useRecoilValue } from 'recoil'; +import { useEffect, useMemo, useState } from 'react'; import OpenAddModalButton from '@/components/yearperiods/OpenAddModalButton'; import OpenDeleteModalButton from '@/components/yearperiods/OpenDeleteModalButton'; import OpenEditModalButton from '@/components/yearperiods/OpenEditModalButton'; -import { userAtom } from '@/store/atoms'; +import { useUserStore } from '@/store'; import { get } from '@api/api_methods'; import { Card, Title } from '@components/common'; import MainLayout from '@components/layout/MainLayout/MainLayout'; -import { YearPeriod, User } from '@type/common'; +import { User, YearPeriod } from '@type/common'; interface Props { yearPeriods: YearPeriod[]; @@ -32,7 +31,7 @@ export default function Periods(props: Props) { const { yearPeriods } = props; const router = useRouter(); - const user = useRecoilValue(userAtom); + const user = useUserStore((state) => state.user); const [currentUser, setCurrentUser] = useState(); const formatYearPeriods = From e85f27372ebb323b02fe3c02b456814a020d29ec Mon Sep 17 00:00:00 2001 From: TkymHrt <23.h.takayama.nutfes@gmail.com> Date: Tue, 13 Jan 2026 00:32:55 +0900 Subject: [PATCH 5/9] refactor: remove RecoilRoot decorators from story files in favor of Zustand --- .../src/stories/auth/SignInView.stories.tsx | 9 --------- .../src/stories/auth/SignUpView.stories.tsx | 9 --------- .../src/stories/common/ChakraUIDropdown.stories.tsx | 9 --------- .../src/stories/common/Header.stories.tsx | 9 --------- .../stories/purchasereports/DetailModal.stories.tsx | 11 +---------- .../src/stories/purchasereports/EditModal.stories.tsx | 9 --------- .../PurchaseReportAddModal.stories.tsx | 9 --------- .../PurchaseReportConfirmModal.stories.tsx | 9 --------- .../PurchaseReportItemNumModal.stories.tsx | 9 --------- .../src/stories/yearperiods/AddModal.stories.tsx | 9 --------- 10 files changed, 1 insertion(+), 91 deletions(-) diff --git a/view/next-project/src/stories/auth/SignInView.stories.tsx b/view/next-project/src/stories/auth/SignInView.stories.tsx index 552a44a57..2d38d69d8 100644 --- a/view/next-project/src/stories/auth/SignInView.stories.tsx +++ b/view/next-project/src/stories/auth/SignInView.stories.tsx @@ -1,5 +1,3 @@ -import { RecoilRoot } from 'recoil'; - import { SignInView } from '@components/auth'; import type { Meta, StoryFn } from '@storybook/react'; @@ -7,13 +5,6 @@ import type { Meta, StoryFn } from '@storybook/react'; const meta: Meta = { title: 'FinanSu/auth/SignInView', component: SignInView, - decorators: [ - (Story) => ( - - - - ), - ], tags: ['autodocs'], argTypes: {}, }; diff --git a/view/next-project/src/stories/auth/SignUpView.stories.tsx b/view/next-project/src/stories/auth/SignUpView.stories.tsx index 390d2ec1e..1f8e6d1ce 100644 --- a/view/next-project/src/stories/auth/SignUpView.stories.tsx +++ b/view/next-project/src/stories/auth/SignUpView.stories.tsx @@ -1,5 +1,3 @@ -import { RecoilRoot } from 'recoil'; - import { SignUpView } from '@components/auth'; import type { Meta, StoryFn } from '@storybook/react'; @@ -7,13 +5,6 @@ import type { Meta, StoryFn } from '@storybook/react'; const meta: Meta = { title: 'FinanSu/auth/SignUpView', component: SignUpView, - decorators: [ - (Story) => ( - - - - ), - ], tags: ['autodocs'], argTypes: {}, }; diff --git a/view/next-project/src/stories/common/ChakraUIDropdown.stories.tsx b/view/next-project/src/stories/common/ChakraUIDropdown.stories.tsx index b249e9155..ae7d63363 100644 --- a/view/next-project/src/stories/common/ChakraUIDropdown.stories.tsx +++ b/view/next-project/src/stories/common/ChakraUIDropdown.stories.tsx @@ -1,5 +1,3 @@ -import { RecoilRoot } from 'recoil'; - import { ChakraUIDropdown } from '@components/common'; import type { Meta, StoryFn } from '@storybook/react'; @@ -7,13 +5,6 @@ import type { Meta, StoryFn } from '@storybook/react'; const meta: Meta = { title: 'FinanSu/common/ChakraUIDropdown', component: ChakraUIDropdown, - decorators: [ - (Story) => ( - - - - ), - ], tags: ['autodocs'], argTypes: {}, }; diff --git a/view/next-project/src/stories/common/Header.stories.tsx b/view/next-project/src/stories/common/Header.stories.tsx index 219acc01e..e712e916a 100644 --- a/view/next-project/src/stories/common/Header.stories.tsx +++ b/view/next-project/src/stories/common/Header.stories.tsx @@ -1,5 +1,3 @@ -import { RecoilRoot } from 'recoil'; - import { Header } from '@components/common'; import type { Meta, StoryFn } from '@storybook/react'; @@ -7,13 +5,6 @@ import type { Meta, StoryFn } from '@storybook/react'; const meta: Meta = { title: 'FinanSu/common/Header', component: Header, - decorators: [ - (Story) => ( - - - - ), - ], tags: ['autodocs'], argTypes: {}, }; diff --git a/view/next-project/src/stories/purchasereports/DetailModal.stories.tsx b/view/next-project/src/stories/purchasereports/DetailModal.stories.tsx index 3a877905c..035e3f0eb 100644 --- a/view/next-project/src/stories/purchasereports/DetailModal.stories.tsx +++ b/view/next-project/src/stories/purchasereports/DetailModal.stories.tsx @@ -1,21 +1,12 @@ -import { RecoilRoot } from 'recoil'; - import { DetailModal } from '@components/purchasereports/'; -import { PURCHASE_REPORT_VIEW, EXPENSES } from '../constants'; +import { EXPENSES, PURCHASE_REPORT_VIEW } from '../constants'; import type { Meta, StoryFn } from '@storybook/react'; const meta: Meta = { title: 'FinanSu/purchasereports/DetailModal', component: DetailModal, - decorators: [ - (Story) => ( - - - - ), - ], tags: ['autodocs'], argTypes: {}, }; diff --git a/view/next-project/src/stories/purchasereports/EditModal.stories.tsx b/view/next-project/src/stories/purchasereports/EditModal.stories.tsx index 511469c26..278ea4197 100644 --- a/view/next-project/src/stories/purchasereports/EditModal.stories.tsx +++ b/view/next-project/src/stories/purchasereports/EditModal.stories.tsx @@ -1,5 +1,3 @@ -import { RecoilRoot } from 'recoil'; - import { EditModal } from '@components/purchasereports'; import type { Meta, StoryFn } from '@storybook/react'; @@ -7,13 +5,6 @@ import type { Meta, StoryFn } from '@storybook/react'; const meta: Meta = { title: 'FinanSu/purchasereports/EditModal', component: EditModal, - decorators: [ - (Story) => ( - - - - ), - ], tags: ['autodocs'], argTypes: {}, }; diff --git a/view/next-project/src/stories/purchasereports/PurchaseReportAddModal.stories.tsx b/view/next-project/src/stories/purchasereports/PurchaseReportAddModal.stories.tsx index 20fad4105..d9c846e67 100644 --- a/view/next-project/src/stories/purchasereports/PurchaseReportAddModal.stories.tsx +++ b/view/next-project/src/stories/purchasereports/PurchaseReportAddModal.stories.tsx @@ -1,5 +1,3 @@ -import { RecoilRoot } from 'recoil'; - import { PurchaseReportAddModal } from '@components/purchasereports'; import type { Meta, StoryFn } from '@storybook/react'; @@ -7,13 +5,6 @@ import type { Meta, StoryFn } from '@storybook/react'; const meta: Meta = { title: 'FinanSu/purchasereports/PurchaseReportAddModal', component: PurchaseReportAddModal, - decorators: [ - (Story) => ( - - - - ), - ], tags: ['autodocs'], argTypes: {}, }; diff --git a/view/next-project/src/stories/purchasereports/PurchaseReportConfirmModal.stories.tsx b/view/next-project/src/stories/purchasereports/PurchaseReportConfirmModal.stories.tsx index 10ed65684..f531a0146 100644 --- a/view/next-project/src/stories/purchasereports/PurchaseReportConfirmModal.stories.tsx +++ b/view/next-project/src/stories/purchasereports/PurchaseReportConfirmModal.stories.tsx @@ -1,5 +1,3 @@ -import { RecoilRoot } from 'recoil'; - import { PurchaseReportConfirmModal } from '@components/purchasereports'; import { PURCHASE_ITEM } from '../constants'; @@ -9,13 +7,6 @@ import type { Meta, StoryFn } from '@storybook/react'; const meta: Meta = { title: 'FinanSu/purchasereports/PurchaseReportConfirmModal', component: PurchaseReportConfirmModal, - decorators: [ - (Story) => ( - - - - ), - ], tags: ['autodocs'], argTypes: {}, }; diff --git a/view/next-project/src/stories/purchasereports/PurchaseReportItemNumModal.stories.tsx b/view/next-project/src/stories/purchasereports/PurchaseReportItemNumModal.stories.tsx index 834557b95..4c5e604aa 100644 --- a/view/next-project/src/stories/purchasereports/PurchaseReportItemNumModal.stories.tsx +++ b/view/next-project/src/stories/purchasereports/PurchaseReportItemNumModal.stories.tsx @@ -1,5 +1,3 @@ -import { RecoilRoot } from 'recoil'; - import { PurchaseReportItemNumModal } from '@components/purchasereports'; import type { Meta } from '@storybook/react'; @@ -7,13 +5,6 @@ import type { Meta } from '@storybook/react'; const meta: Meta = { title: 'FinanSu/purchasereports/PurchaseReportItemNumModal', component: PurchaseReportItemNumModal, - decorators: [ - (Story) => ( - - - - ), - ], tags: ['autodocs'], argTypes: {}, }; diff --git a/view/next-project/src/stories/yearperiods/AddModal.stories.tsx b/view/next-project/src/stories/yearperiods/AddModal.stories.tsx index 8070bd4d3..c72bcdd39 100644 --- a/view/next-project/src/stories/yearperiods/AddModal.stories.tsx +++ b/view/next-project/src/stories/yearperiods/AddModal.stories.tsx @@ -1,6 +1,4 @@ // /Users/kobayashiryota/Workspace/FinanSu/view/next-project/src/stories/yearperiods/AddModal.stories.tsx -import { RecoilRoot } from 'recoil'; - import { AddModal } from '@components/yearperiods'; import type { Meta, StoryFn } from '@storybook/react'; @@ -8,13 +6,6 @@ import type { Meta, StoryFn } from '@storybook/react'; const meta: Meta = { title: 'FinanSu/yearperiods/AddModal', component: AddModal, - decorators: [ - (Story) => ( - - - - ), - ], argTypes: {}, tags: ['autodocs'], }; From 946a4c727824e4ee3f3d1a4ec51949e3675147fc Mon Sep 17 00:00:00 2001 From: TkymHrt <23.h.takayama.nutfes@gmail.com> Date: Tue, 13 Jan 2026 00:55:50 +0900 Subject: [PATCH 6/9] refactor: update dependencies in useEffect for session validation in MainLayout --- .../src/components/layout/MainLayout/MainLayout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/view/next-project/src/components/layout/MainLayout/MainLayout.tsx b/view/next-project/src/components/layout/MainLayout/MainLayout.tsx index 811c32a9d..7ad272541 100644 --- a/view/next-project/src/components/layout/MainLayout/MainLayout.tsx +++ b/view/next-project/src/components/layout/MainLayout/MainLayout.tsx @@ -58,7 +58,7 @@ export default function MainLayout(props: LayoutProps) { validateSession(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [hasHydrated, router.pathname]); + }, [hasHydrated, router.pathname, isSignIn, accessToken, resetAuth, resetUser]); if (!hasHydrated || isChecking) { return ( From 0645514d8f0977f04b702346e0fa7cd3cf040af7 Mon Sep 17 00:00:00 2001 From: TkymHrt <23.h.takayama.nutfes@gmail.com> Date: Sun, 18 Jan 2026 22:17:21 +0900 Subject: [PATCH 7/9] refactor: add permission fix for volume ownership in setup and build processes --- Makefile | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 579954f39..56105ca22 100644 --- a/Makefile +++ b/Makefile @@ -52,8 +52,14 @@ setup: ## 開発環境をセットアップ (build > run-db > run) @echo "$(GREEN)--- Setup completed! ---$(RESET)" ##@ 基本操作 +fix-perms: ## ボリュームの所有権を一般ユーザー(1000)に変更 + @echo "$(GREEN)--- Fixing volume permissions... ---$(RESET)" + docker compose run --rm --user root view chown -R 1000:1000 /app/.pnpm-store + docker compose run --rm --user root api chown -R 1000:1000 /go/cache /go/pkg/mod + build: ## アプリコンテナのイメージをビルド docker compose build + make fix-perms docker compose run --rm view pnpm install build-stg: ## ステージング環境ビルド @@ -71,7 +77,9 @@ build-run: ## ビルドと起動を同時実行 run-rebuild: ## ボリューム削除→ビルド→起動 docker compose down -v - docker compose up --build + docker compose build + make fix-perms + docker compose up -d restart: ## アプリコンテナの再起動 (DBは維持) @echo "$(GREEN)--- Restarting App Containers ---$(RESET)" From bc94d246ed6e5e594838db2f2472e2a8a355aa60 Mon Sep 17 00:00:00 2001 From: TkymHrt <23.h.takayama.nutfes@gmail.com> Date: Tue, 20 Jan 2026 18:04:34 +0900 Subject: [PATCH 8/9] refactor: replace useUserStore with useCurrentUser for user state management across components --- .../create_purchase_report/usePurchaseReportForm.ts | 4 ++-- .../src/components/purchasereports/DetailPage1.tsx | 4 ++-- .../next-project/src/components/purchasereports/EditModal.tsx | 4 ++-- .../src/components/purchasereports/PurchaseReportAddModal.tsx | 4 ++-- .../components/purchasereports/PurchaseReportItemNumModal.tsx | 4 ++-- view/next-project/src/pages/budget_managements/index.tsx | 4 ++-- view/next-project/src/pages/fund_informations/index.tsx | 4 ++-- view/next-project/src/pages/my_page/index.tsx | 4 ++-- view/next-project/src/pages/purchase_report_list/index.tsx | 4 ++-- view/next-project/src/pages/teachers/index.tsx | 4 ++-- view/next-project/src/pages/users/index.tsx | 4 ++-- view/next-project/src/pages/yearperiods/index.tsx | 4 ++-- view/next-project/src/store/index.ts | 2 +- view/next-project/src/store/userStore.ts | 2 ++ 14 files changed, 27 insertions(+), 25 deletions(-) diff --git a/view/next-project/src/components/create_purchase_report/usePurchaseReportForm.ts b/view/next-project/src/components/create_purchase_report/usePurchaseReportForm.ts index cd4637c71..8c7994295 100644 --- a/view/next-project/src/components/create_purchase_report/usePurchaseReportForm.ts +++ b/view/next-project/src/components/create_purchase_report/usePurchaseReportForm.ts @@ -9,7 +9,7 @@ import { usePutBuyReportsId, } from '@/generated/hooks'; import { DivisionOption, FestivalItemOption } from '@/generated/model'; -import { useUserStore } from '@/store'; +import { useCurrentUser } from '@/store'; import type { BuyReport, PostBuyReportsBody, PutBuyReportsIdBody } from '@/generated/model'; @@ -48,7 +48,7 @@ export const usePurchaseReportForm = (router: NextRouter) => { const reportId = reportIdParam ? Number(reportIdParam) : undefined; const isEditMode = from === 'purchase_report_list'; - const user = useUserStore((state) => state.user); + const user = useCurrentUser(); const [departments, setDepartments] = useState([]); const [uploadedFile, setUploadedFile] = useState(null); const [festivalItems, setFestivalItems] = useState([]); diff --git a/view/next-project/src/components/purchasereports/DetailPage1.tsx b/view/next-project/src/components/purchasereports/DetailPage1.tsx index be7aab1c0..e3afff9f7 100644 --- a/view/next-project/src/components/purchasereports/DetailPage1.tsx +++ b/view/next-project/src/components/purchasereports/DetailPage1.tsx @@ -4,7 +4,7 @@ import { FaChevronCircleRight } from 'react-icons/fa'; import { RiExternalLinkLine, RiFileCopyLine } from 'react-icons/ri'; import PrimaryButton from '@/components/common/OutlinePrimaryButton/OutlinePrimaryButton'; -import { useUserStore } from '@/store'; +import { useCurrentUser } from '@/store'; import { downloadFile } from '@/utils/downloadFile'; import { del } from '@api/api_methods'; import { Checkbox, RedButton, Tooltip } from '@components/common'; @@ -21,7 +21,7 @@ interface DetailModalProps { } const DetailPage1: FC = (props) => { - const user = useUserStore((state) => state.user); + const user = useCurrentUser(); const [date, setDate] = useState(String); const [japaneseDate, setJapaneseDate] = useState(String); diff --git a/view/next-project/src/components/purchasereports/EditModal.tsx b/view/next-project/src/components/purchasereports/EditModal.tsx index e0b6c80ff..c53b5faf9 100644 --- a/view/next-project/src/components/purchasereports/EditModal.tsx +++ b/view/next-project/src/components/purchasereports/EditModal.tsx @@ -2,7 +2,7 @@ import { useRouter } from 'next/router'; import React, { useCallback, useEffect, useState } from 'react'; import { RiArrowDropRightLine } from 'react-icons/ri'; -import { useUserStore } from '@/store'; +import { useCurrentUser } from '@/store'; import { get, put as putPurchaseReport } from '@api/api_methods'; import { put as putPurchaseItem } from '@api/purchaseItem'; import { @@ -25,7 +25,7 @@ interface ModalProps { } export default function EditModal(props: ModalProps) { - const user = useUserStore((state) => state.user); + const user = useCurrentUser(); const router = useRouter(); diff --git a/view/next-project/src/components/purchasereports/PurchaseReportAddModal.tsx b/view/next-project/src/components/purchasereports/PurchaseReportAddModal.tsx index a0e65eeb0..eab81c5e1 100644 --- a/view/next-project/src/components/purchasereports/PurchaseReportAddModal.tsx +++ b/view/next-project/src/components/purchasereports/PurchaseReportAddModal.tsx @@ -2,7 +2,7 @@ import { useRouter } from 'next/router'; import React, { useCallback, useEffect, useState } from 'react'; import { RiArrowDropRightLine } from 'react-icons/ri'; -import { useUserStore } from '@/store'; +import { useCurrentUser } from '@/store'; import { get, post } from '@api/api_methods'; import { post as postItem, put } from '@api/purchaseItem'; import { post as postOrder } from '@api/purchaseOrder'; @@ -35,7 +35,7 @@ interface ModalProps { } export default function PurchaseReportAddModal(props: ModalProps) { - const user = useUserStore((state) => state.user); + const user = useCurrentUser(); const router = useRouter(); diff --git a/view/next-project/src/components/purchasereports/PurchaseReportItemNumModal.tsx b/view/next-project/src/components/purchasereports/PurchaseReportItemNumModal.tsx index bf206485d..e843f2fb6 100644 --- a/view/next-project/src/components/purchasereports/PurchaseReportItemNumModal.tsx +++ b/view/next-project/src/components/purchasereports/PurchaseReportItemNumModal.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; -import { useUserStore } from '@/store'; +import { useCurrentUser } from '@/store'; import { CloseButton, Modal, @@ -29,7 +29,7 @@ export default function PurchaseReportItemNumModal() { getPeriods(); }, []); - const user = useUserStore((state) => state.user); + const user = useCurrentUser(); const [expenses, setExpenses] = useState([]); const [expenseID, setExpenseID] = useState(0); diff --git a/view/next-project/src/pages/budget_managements/index.tsx b/view/next-project/src/pages/budget_managements/index.tsx index 1b411c810..c60f4ba8b 100644 --- a/view/next-project/src/pages/budget_managements/index.tsx +++ b/view/next-project/src/pages/budget_managements/index.tsx @@ -2,7 +2,7 @@ import router from 'next/router'; import BudgetManagement from '@/components/budget_managements/BudgetManagement'; import MainLayout from '@/components/layout/MainLayout'; -import { useUserStore } from '@/store'; +import { useCurrentUser } from '@/store'; import { Year } from '@/type/common'; import { get } from '@/utils/api/api_methods'; @@ -21,7 +21,7 @@ export async function getServerSideProps() { } export default function Home(props: Props) { - const user = useUserStore((state) => state.user); + const user = useCurrentUser(); user?.roleID === 1 && router.push('/my_page'); return ( diff --git a/view/next-project/src/pages/fund_informations/index.tsx b/view/next-project/src/pages/fund_informations/index.tsx index 50039c4a0..7474505c8 100644 --- a/view/next-project/src/pages/fund_informations/index.tsx +++ b/view/next-project/src/pages/fund_informations/index.tsx @@ -3,12 +3,12 @@ import router from 'next/router'; import { FundInformationHeader, FundInformationTable } from '@/components/fund_information'; import { useFundInformations } from '@/components/fund_information/useFundInformations'; -import { useUserStore } from '@/store'; +import { useCurrentUser } from '@/store'; import { Card } from '@components/common'; import MainLayout from '@components/layout/MainLayout'; export default function FundInformations() { - const user = useUserStore((state) => state.user); + const user = useCurrentUser(); user?.roleID === 1 && router.push('/my_page'); diff --git a/view/next-project/src/pages/my_page/index.tsx b/view/next-project/src/pages/my_page/index.tsx index 3257b6386..7d27a68cd 100644 --- a/view/next-project/src/pages/my_page/index.tsx +++ b/view/next-project/src/pages/my_page/index.tsx @@ -6,14 +6,14 @@ import { Card, Loading, PrimaryButton } from '@/components/common'; import MainLayout from '@/components/layout/MainLayout'; import TableSection from '@/components/mypage/TableSection'; import { useGetFestivalItemsDetailsUserId } from '@/generated/hooks'; -import { useUserStore } from '@/store'; +import { useCurrentUser } from '@/store'; import { User } from '@/type/common'; import { notoSansJP } from '../_app'; const MyPage = () => { const router = useRouter(); - const user = useUserStore((state) => state.user); + const user = useCurrentUser(); const [currentUser, setCurrentUser] = useState(); useEffect(() => { diff --git a/view/next-project/src/pages/purchase_report_list/index.tsx b/view/next-project/src/pages/purchase_report_list/index.tsx index aa528a190..149eb2f81 100644 --- a/view/next-project/src/pages/purchase_report_list/index.tsx +++ b/view/next-project/src/pages/purchase_report_list/index.tsx @@ -11,7 +11,7 @@ import { useGetYearsPeriods, usePutBuyReportStatusBuyReportId, } from '@/generated/hooks'; -import { useUserStore } from '@/store'; +import { useCurrentUser } from '@/store'; import { Card, Checkbox, EditButton, Loading, Title } from '@components/common'; import MainLayout from '@components/layout/MainLayout'; import OpenDeleteModalButton from '@components/purchasereports/OpenDeleteModalButton'; @@ -30,7 +30,7 @@ export default function PurchaseReports() { error: yearPeriodsError, } = useGetYearsPeriods(); const yearPeriods = yearPeriodsData?.data; - const user = useUserStore((state) => state.user); + const user = useCurrentUser(); user?.roleID === 1 && router.push('/my_page'); diff --git a/view/next-project/src/pages/teachers/index.tsx b/view/next-project/src/pages/teachers/index.tsx index 4c0afc2ec..c4f6dcd52 100644 --- a/view/next-project/src/pages/teachers/index.tsx +++ b/view/next-project/src/pages/teachers/index.tsx @@ -2,7 +2,7 @@ import clsx from 'clsx'; import Head from 'next/head'; import { useEffect, useState } from 'react'; -import { useUserStore } from '@/store'; +import { useCurrentUser } from '@/store'; import { get } from '@api/api_methods'; import { Card, Title } from '@components/common'; import MainLayout from '@components/layout/MainLayout'; @@ -41,7 +41,7 @@ export default function TeachersList(props: Props) { departments[0], ); - const user = useUserStore((state) => state.user); + const user = useCurrentUser(); const [currentUser, setCurrentUser] = useState(); const isDisabled = !( currentUser?.roleID === 2 || diff --git a/view/next-project/src/pages/users/index.tsx b/view/next-project/src/pages/users/index.tsx index 50a541c17..c13e13afe 100644 --- a/view/next-project/src/pages/users/index.tsx +++ b/view/next-project/src/pages/users/index.tsx @@ -4,7 +4,7 @@ import { useRouter } from 'next/router'; import { useEffect, useMemo, useState } from 'react'; import OpenDeleteModalButton from '@/components/users/OpenDeleteModalButton'; -import { useUserStore } from '@/store'; +import { useCurrentUser } from '@/store'; import { get } from '@api/api_methods'; import { Card, Title } from '@components/common'; import MainLayout from '@components/layout/MainLayout/MainLayout'; @@ -35,7 +35,7 @@ export default function Users(props: Props) { const { users, bureaus } = props; const router = useRouter(); - const user = useUserStore((state) => state.user); + const user = useCurrentUser(); const [currentUser, setCurrentUser] = useState(); const [selectedBureau, setSelectedBureau] = useState(0); const [filterUsers, setFilterUsers] = useState(users); diff --git a/view/next-project/src/pages/yearperiods/index.tsx b/view/next-project/src/pages/yearperiods/index.tsx index 359820581..a0cf7e956 100644 --- a/view/next-project/src/pages/yearperiods/index.tsx +++ b/view/next-project/src/pages/yearperiods/index.tsx @@ -6,7 +6,7 @@ import { useEffect, useMemo, useState } from 'react'; import OpenAddModalButton from '@/components/yearperiods/OpenAddModalButton'; import OpenDeleteModalButton from '@/components/yearperiods/OpenDeleteModalButton'; import OpenEditModalButton from '@/components/yearperiods/OpenEditModalButton'; -import { useUserStore } from '@/store'; +import { useCurrentUser } from '@/store'; import { get } from '@api/api_methods'; import { Card, Title } from '@components/common'; import MainLayout from '@components/layout/MainLayout/MainLayout'; @@ -31,7 +31,7 @@ export default function Periods(props: Props) { const { yearPeriods } = props; const router = useRouter(); - const user = useUserStore((state) => state.user); + const user = useCurrentUser(); const [currentUser, setCurrentUser] = useState(); const formatYearPeriods = diff --git a/view/next-project/src/store/index.ts b/view/next-project/src/store/index.ts index 5007e1770..b07d9a72c 100644 --- a/view/next-project/src/store/index.ts +++ b/view/next-project/src/store/index.ts @@ -1,2 +1,2 @@ export { useAuthStore } from './authStore'; -export { useUserStore } from './userStore'; +export { useCurrentUser, useUserStore } from './userStore'; diff --git a/view/next-project/src/store/userStore.ts b/view/next-project/src/store/userStore.ts index 23911e2cb..fba51ef26 100644 --- a/view/next-project/src/store/userStore.ts +++ b/view/next-project/src/store/userStore.ts @@ -42,3 +42,5 @@ export const useUserStore = create()( }, ), ); + +export const useCurrentUser = () => useUserStore((state) => state.user); From f29a65e2c07ca724558946f150e2e072ed2b07f8 Mon Sep 17 00:00:00 2001 From: TkymHrt <23.h.takayama.nutfes@gmail.com> Date: Tue, 20 Jan 2026 18:05:29 +0900 Subject: [PATCH 9/9] refactor: optimize user session validation and improve login page handling in MainLayout --- .../layout/MainLayout/MainLayout.tsx | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/view/next-project/src/components/layout/MainLayout/MainLayout.tsx b/view/next-project/src/components/layout/MainLayout/MainLayout.tsx index 7ad272541..ee64a8b63 100644 --- a/view/next-project/src/components/layout/MainLayout/MainLayout.tsx +++ b/view/next-project/src/components/layout/MainLayout/MainLayout.tsx @@ -10,6 +10,8 @@ import 'tailwindcss/tailwind.css'; import s from './MainLayout.module.css'; +const CURRENT_USER_URL = process.env.CSR_API_URI + '/current_user'; + interface LayoutProps { children?: React.ReactNode; } @@ -22,6 +24,8 @@ export default function MainLayout(props: LayoutProps) { const [isChecking, setIsChecking] = useState(true); + const isLoginPage = router.pathname === '/'; + const hasHydrated = authHasHydrated && userHasHydrated; useEffect(() => { @@ -33,15 +37,14 @@ export default function MainLayout(props: LayoutProps) { return; } - const getCurrentUserUrl = process.env.CSR_API_URI + '/current_user'; - const isValid = await get_with_token_valid(getCurrentUserUrl, accessToken); + const isValid = await get_with_token_valid(CURRENT_USER_URL, accessToken); if (!isValid) { await handleLogout(); + } else if (router.pathname === '/') { + await router.push('/my_page'); + setIsChecking(false); } else { - if (router.pathname === '/') { - await router.push('/my_page'); - } setIsChecking(false); } }; @@ -50,7 +53,7 @@ export default function MainLayout(props: LayoutProps) { resetAuth(); resetUser(); - if (router.pathname !== '/') { + if (!isLoginPage) { await router.push('/'); } setIsChecking(false); @@ -77,12 +80,10 @@ export default function MainLayout(props: LayoutProps) {
- {router.pathname !== '/' && ( -
setIsSideNavOpen(!isSideNavOpen)} /> - )} + {!isLoginPage &&
setIsSideNavOpen(!isSideNavOpen)} />}
- {router.pathname !== '/' && ( + {!isLoginPage && (
)}
{props.children}