From 76c229599f887b923680a3fb106781470ad793a3 Mon Sep 17 00:00:00 2001
From: dorimu0 <121004915+dorimu0@users.noreply.github.com>
Date: Wed, 24 Apr 2024 01:00:48 +0900
Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20feat=20:=20Add=20class=20user?=
=?UTF-8?q?=20info=20api?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Add API to get class user information via cid passed as a query
- Modify login state management logic
- Add permission enum for class user
Related issue: #104
---
src/api/apiUtils.ts | 1 +
src/api/classUser/getClassInfo.ts | 10 +++
src/app/intro/googleLogin/page.tsx | 1 -
src/app/layout.tsx | 15 ++--
src/components/navbar/Navbar.tsx | 12 ++-
src/components/navbar/profile/Profile.tsx | 97 ++++++++++++++---------
src/components/protect/Protect.tsx | 20 -----
src/components/protect/index.ts | 3 -
src/constants/roles.ts | 10 +++
src/interfaces/user/ClassUser.ts | 8 ++
src/interfaces/user/index.ts | 3 +-
src/recoil/atoms/classUserState.ts | 13 +++
src/recoil/atoms/userState.ts | 8 +-
13 files changed, 121 insertions(+), 80 deletions(-)
create mode 100644 src/api/classUser/getClassInfo.ts
delete mode 100644 src/components/protect/Protect.tsx
delete mode 100644 src/components/protect/index.ts
create mode 100644 src/constants/roles.ts
create mode 100644 src/interfaces/user/ClassUser.ts
create mode 100644 src/recoil/atoms/classUserState.ts
diff --git a/src/api/apiUtils.ts b/src/api/apiUtils.ts
index 661873e..c463a17 100644
--- a/src/api/apiUtils.ts
+++ b/src/api/apiUtils.ts
@@ -40,6 +40,7 @@ api.interceptors.response.use(
}
} catch (error) {
console.error('トークンの有効期限が切れました。');
+ window.location.href = '/intro';
}
}
return Promise.reject(error);
diff --git a/src/api/classUser/getClassInfo.ts b/src/api/classUser/getClassInfo.ts
new file mode 100644
index 0000000..e9248bd
--- /dev/null
+++ b/src/api/classUser/getClassInfo.ts
@@ -0,0 +1,10 @@
+import req from '../apiUtils';
+
+const getClassInfo = async (uId: number, cId: number) => {
+ const response = await req(`/cu/${uId}/${cId}/info`, 'get', 'gin');
+ console.log(response);
+
+ return response.data;
+};
+
+export default getClassInfo;
diff --git a/src/app/intro/googleLogin/page.tsx b/src/app/intro/googleLogin/page.tsx
index c88bdf3..ab1761a 100644
--- a/src/app/intro/googleLogin/page.tsx
+++ b/src/app/intro/googleLogin/page.tsx
@@ -17,7 +17,6 @@ const Page = () => {
const setRefreshToken = useSetRecoilState(refreshTokenState);
const router = useRouter();
useEffect(() => {
- console.log(code);
if (code) {
postGoogleLogin(code).then(res => {
if (res.user) {
diff --git a/src/app/layout.tsx b/src/app/layout.tsx
index ebff2b8..5e5b4d7 100644
--- a/src/app/layout.tsx
+++ b/src/app/layout.tsx
@@ -2,7 +2,6 @@ import type {Metadata} from 'next';
import {Inter} from 'next/font/google';
import {Navbar} from '../components/navbar';
import {Footer} from '../components/footer';
-import Protect from '../components/protect';
import RecoilRootContainer from '../components/RecoilRootContainer';
import './globals.css';
import '@/src/styles/variable.css';
@@ -19,15 +18,13 @@ const RootLayout = ({children}: {children: React.ReactNode}) => {
-
-
-
-
+
diff --git a/src/components/navbar/Navbar.tsx b/src/components/navbar/Navbar.tsx
index 9805cf0..a3b4e6f 100644
--- a/src/components/navbar/Navbar.tsx
+++ b/src/components/navbar/Navbar.tsx
@@ -2,17 +2,13 @@
import {useState} from 'react';
import Image from 'next/image';
import Link from 'next/link';
-import {useParams, usePathname} from 'next/navigation';
-import {useRecoilValue} from 'recoil';
-import userState from '@/src/recoil/atoms/userState';
+import {useParams, usePathname, useSearchParams} from 'next/navigation';
import {MaterialContainer, MaterialForm} from './material';
import Profile from './profile';
-import {User} from '@/src/interfaces/user';
import icons from '@/public/svgs/navbar';
import '@/src/styles/variable.css';
const Navbar = () => {
- const user = useRecoilValue(userState) as User;
const [isOpen, setIsOpen] = useState
(false);
const pages = [
@@ -24,6 +20,8 @@ const Navbar = () => {
const router = usePathname();
const params = useParams<{className: string; materialName: string}>();
+ const searchParams = useSearchParams();
+ const search = searchParams.get('id');
if (router === '/intro' || router === '/intro/googleLogin') {
return null;
@@ -33,7 +31,7 @@ const Navbar = () => {
{/* Profile */}
-
+
@@ -82,7 +80,7 @@ const Navbar = () => {
{isOpen ?
: null}
-
+
diff --git a/src/components/navbar/profile/Profile.tsx b/src/components/navbar/profile/Profile.tsx
index 0e4f341..cf370a0 100644
--- a/src/components/navbar/profile/Profile.tsx
+++ b/src/components/navbar/profile/Profile.tsx
@@ -1,20 +1,37 @@
-import {useState} from 'react';
+import {useEffect, useState} from 'react';
import Image from 'next/image';
import {useRouter} from 'next/navigation';
+import {useRecoilState, useRecoilValue} from 'recoil';
import EditName from './EditName';
import Warning from '../../warning/Warning';
+import getClassInfo from '@/src/api/classUser/getClassInfo';
import putUserName from '@/src/api/classUser/putUserName';
+import classUserState from '@/src/recoil/atoms/classUserState';
+import userState from '@/src/recoil/atoms/userState';
import {ParamsProps} from '@/src/interfaces/navbar';
-import {User} from '@/src/interfaces/user';
-import ClassUser from '@/src/model/User';
import icons from '@/public/svgs/navbar';
+import ROLES from '@/src/constants/roles';
-const Profile = ({user, params}: {user: User; params: ParamsProps}) => {
+const Profile = ({cId, params}: {cId: string | null; params: ParamsProps}) => {
const router = useRouter();
+ const user = useRecoilValue(userState);
+ const [classUser, setClassUser] = useRecoilState(classUserState);
const [dropdownOpen, setDropdownOpen] = useState(false);
const [isEditOpen, setIsEditOpen] = useState(false);
const [isOpen, setIsOpen] = useState(false);
+ useEffect(() => {
+ if (cId && !classUser) {
+ getClassInfo(user.id, parseInt(cId)).then(res => {
+ console.log(res);
+ setClassUser(res);
+ });
+ }
+ if (!params.className) {
+ setClassUser(null);
+ }
+ }, [cId, classUser, params]);
+
const toggleDropdown = () => {
setDropdownOpen(!dropdownOpen);
console.log(params);
@@ -22,7 +39,7 @@ const Profile = ({user, params}: {user: User; params: ParamsProps}) => {
const handleEditName = (name: string) => {
setDropdownOpen(false);
- putUserName(user.id, 4, name);
+ if (classUser) putUserName(classUser.uid, 4, name);
};
const handleClickDelete = () => {
@@ -38,14 +55,16 @@ const Profile = ({user, params}: {user: User; params: ParamsProps}) => {
-
{user.name}
+
+ {classUser ? classUser.nickname : user ? user.name : ''}
+
{dropdownOpen && (
- - {
- setIsEditOpen(true);
- setDropdownOpen(false);
- }}
- >
- Edit Name
-
- {ClassUser.managerRoll === 'manager' ? (
- - {
- setIsOpen(true);
- setDropdownOpen(false);
- }}
- >
- Edit group
-
+ {classUser ? (
+ <>
+ - {
+ setIsEditOpen(true);
+ setDropdownOpen(false);
+ }}
+ >
+ Edit Name
+
+ {ROLES[classUser.role_id] === 'ADMIN' ? (
+ - {
+ setIsOpen(true);
+ setDropdownOpen(false);
+ }}
+ >
+ Edit group
+
+ ) : null}
+ - {
+ setIsOpen(true);
+ setDropdownOpen(false);
+ }}
+ >
+ {ROLES[classUser.role_id] === 'ADMIN'
+ ? 'Delete group'
+ : 'Leave group'}
+
+ >
) : null}
- - {
- setIsOpen(true);
- setDropdownOpen(false);
- }}
- >
- {ClassUser.managerRoll === 'manager'
- ? 'Delete group'
- : 'Leave group'}
-
-
Logout
diff --git a/src/components/protect/Protect.tsx b/src/components/protect/Protect.tsx
deleted file mode 100644
index a7a7516..0000000
--- a/src/components/protect/Protect.tsx
+++ /dev/null
@@ -1,20 +0,0 @@
-'use client';
-import {ReactNode, useEffect} from 'react';
-import {useRouter} from 'next/navigation';
-import {useRecoilValue} from 'recoil';
-import userState from '@/src/recoil/atoms/userState';
-
-const Protect = ({children}: {children: ReactNode}) => {
- const user = useRecoilValue(userState);
- const router = useRouter();
-
- useEffect(() => {
- if (!user) {
- router.push('/intro');
- }
- }, [user, router]);
-
- return children;
-};
-
-export default Protect;
diff --git a/src/components/protect/index.ts b/src/components/protect/index.ts
deleted file mode 100644
index 601a5c7..0000000
--- a/src/components/protect/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import Protect from './Protect';
-
-export default Protect;
diff --git a/src/constants/roles.ts b/src/constants/roles.ts
new file mode 100644
index 0000000..55e4b06
--- /dev/null
+++ b/src/constants/roles.ts
@@ -0,0 +1,10 @@
+const ROLES: {[key: number]: string} = {
+ 1: 'USER',
+ 2: 'ADMIN',
+ 3: 'ASSISTANT',
+ 4: 'APPLICANT',
+ 5: 'BLACKLIST',
+ 6: 'INVITE',
+};
+
+export default ROLES;
diff --git a/src/interfaces/user/ClassUser.ts b/src/interfaces/user/ClassUser.ts
new file mode 100644
index 0000000..12fa115
--- /dev/null
+++ b/src/interfaces/user/ClassUser.ts
@@ -0,0 +1,8 @@
+interface ClassUser {
+ uid: number;
+ nickname: string;
+ role_id: number;
+ image: string;
+}
+
+export default ClassUser;
diff --git a/src/interfaces/user/index.ts b/src/interfaces/user/index.ts
index 0b514a2..ad8a1c6 100644
--- a/src/interfaces/user/index.ts
+++ b/src/interfaces/user/index.ts
@@ -2,5 +2,6 @@ import User from './User';
import LoginData from './LoginData';
import AccessToken from './AccessToken';
import RefreshToken from './RefreshToken';
+import ClassUser from './ClassUser';
-export type {User, LoginData, AccessToken, RefreshToken};
+export type {User, LoginData, AccessToken, RefreshToken, ClassUser};
diff --git a/src/recoil/atoms/classUserState.ts b/src/recoil/atoms/classUserState.ts
new file mode 100644
index 0000000..fc7c928
--- /dev/null
+++ b/src/recoil/atoms/classUserState.ts
@@ -0,0 +1,13 @@
+import {atom} from 'recoil';
+import {ClassUser} from '@/src/interfaces/user';
+import {recoilPersist} from 'recoil-persist';
+
+const {persistAtom} = recoilPersist();
+
+const classUserState = atom({
+ key: 'classUserState',
+ default: null,
+ effects_UNSTABLE: [persistAtom],
+});
+
+export default classUserState;
diff --git a/src/recoil/atoms/userState.ts b/src/recoil/atoms/userState.ts
index 77ccac8..a71d3be 100644
--- a/src/recoil/atoms/userState.ts
+++ b/src/recoil/atoms/userState.ts
@@ -4,9 +4,13 @@ import {recoilPersist} from 'recoil-persist';
const {persistAtom} = recoilPersist();
-const userState = atom({
+const userState = atom({
key: 'userState',
- default: null,
+ default: {
+ id: 0,
+ name: '',
+ image: '',
+ },
effects_UNSTABLE: [persistAtom],
});
From c1695d5a52dbdd346c62afc7c02502d6bd20b542 Mon Sep 17 00:00:00 2001
From: dorimu0 <121004915+dorimu0@users.noreply.github.com>
Date: Wed, 24 Apr 2024 01:13:07 +0900
Subject: [PATCH 2/2] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20refactor=20:=20Modify?=
=?UTF-8?q?=20API=20requests=20based=20on=20classId?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
- Modify API requests based on the specified class user on prompt and material pages.
- Fix to get locally stored token in postPrompt function
Related issue: #104
---
src/api/prompts/postPrompt.ts | 7 ++++---
.../components/subComponents/PromptChat.tsx | 7 +++----
.../components/subComponents/Storage.tsx | 2 +-
.../navbar/material/MaterialContainer.tsx | 18 ++++++++++++++----
.../navbar/material/MaterialForm.tsx | 12 +++++++++---
.../navbar/material/MaterialList.tsx | 12 +++++++++---
6 files changed, 40 insertions(+), 18 deletions(-)
diff --git a/src/api/prompts/postPrompt.ts b/src/api/prompts/postPrompt.ts
index 305af6b..c4cf3e3 100644
--- a/src/api/prompts/postPrompt.ts
+++ b/src/api/prompts/postPrompt.ts
@@ -4,18 +4,19 @@ const postPrompt = async (
message: string,
chat: (reader: ReadableStreamDefaultReader) => void
) => {
+ const token = localStorage.getItem('access_token');
+ console.log('token:', token);
const body = {
message: message,
};
+ console.log('body:', body);
try {
const response = await fetch(
`http://3.38.86.236:3000/api/nest/class/${cId}/prompts/${id}`,
{
method: 'POST',
headers: {
- Authorization:
- 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MiwiZXhwIjoxOTY5OTAxMDIyfQ.U0k1q2oTrp3JwsIpem16o2W77tpVGiwylwc5cTFaZgU',
- 'Content-Type': 'application/json',
+ Authorization: `Bearer ${token}`,
},
body: JSON.stringify(body),
}
diff --git a/src/app/[className]/[materialName]/components/subComponents/PromptChat.tsx b/src/app/[className]/[materialName]/components/subComponents/PromptChat.tsx
index 5c5d9b4..7308032 100644
--- a/src/app/[className]/[materialName]/components/subComponents/PromptChat.tsx
+++ b/src/app/[className]/[materialName]/components/subComponents/PromptChat.tsx
@@ -16,14 +16,14 @@ const PromptChat = () => {
const [reload, setReload] = useState(false);
useEffect(() => {
- getPrompt(1, 1, 1, 6).then(res => {
+ getPrompt(4, 126, 1, 6).then(res => {
res.messages.reverse();
setMsg(res.messages);
});
}, [reload]);
const handleClickIcon = (mId: number) => {
- patchMessage(1, 1, mId, true).then(res => {
+ patchMessage(4, 126, mId, true).then(res => {
console.log(res);
});
};
@@ -56,8 +56,7 @@ const PromptChat = () => {
useEffect(() => {
if (inputMsg === '') return;
- postPrompt(1, 1, inputMsg, chat).then(res => {
- console.log(res);
+ postPrompt(4, 126, inputMsg, chat).then(() => {
setInputMsg('');
});
}, [inputMsg]);
diff --git a/src/app/[className]/[materialName]/components/subComponents/Storage.tsx b/src/app/[className]/[materialName]/components/subComponents/Storage.tsx
index cec3ae7..c2c97b5 100644
--- a/src/app/[className]/[materialName]/components/subComponents/Storage.tsx
+++ b/src/app/[className]/[materialName]/components/subComponents/Storage.tsx
@@ -14,7 +14,7 @@ const Storage = () => {
useEffect(() => {
// コメントを取得する処理
- getMessage(1, 1, 1, 5).then(res => {
+ getMessage(4, 126, 1, 5).then(res => {
console.log(res);
setMsg(res);
setIsOpen(new Array(res.length).fill(false)); // コメントの開閉状態を初期化
diff --git a/src/components/navbar/material/MaterialContainer.tsx b/src/components/navbar/material/MaterialContainer.tsx
index e73467a..f7dce35 100644
--- a/src/components/navbar/material/MaterialContainer.tsx
+++ b/src/components/navbar/material/MaterialContainer.tsx
@@ -7,7 +7,13 @@ import searchMaterial from '@/src/api/material/searchMaterial';
import {Material, ParamsProps} from '@/src/interfaces/navbar';
import icons from '@/public/svgs/navbar';
-const MaterialContainer = ({params}: {params: ParamsProps}) => {
+const MaterialContainer = ({
+ params,
+ cId,
+}: {
+ params: ParamsProps;
+ cId: string | null;
+}) => {
const [materials, setMaterials] = useState([]);
const [searchMaterials, setSearchMaterials] = useState([]);
const [keyWord, setKeyWord] = useState('');
@@ -16,7 +22,7 @@ const MaterialContainer = ({params}: {params: ParamsProps}) => {
const onLoadMore = () => {
setHasMore(false);
- getMaterial(1, boardPage, 8).then(res => {
+ getMaterial(4, boardPage, 8).then(res => {
if (res.length === 0) {
setHasMore(false);
} else {
@@ -85,9 +91,13 @@ const MaterialContainer = ({params}: {params: ParamsProps}) => {
>
{materials ? (
keyWord ? (
-
+
) : (
-
+
)
) : null}
diff --git a/src/components/navbar/material/MaterialForm.tsx b/src/components/navbar/material/MaterialForm.tsx
index ebb9ffa..499cbd5 100644
--- a/src/components/navbar/material/MaterialForm.tsx
+++ b/src/components/navbar/material/MaterialForm.tsx
@@ -1,14 +1,20 @@
-import {ChangeEvent, useRef, useState} from 'react';
+import {ChangeEvent, useEffect, useRef, useState} from 'react';
import Image from 'next/image';
import postMaterial from '@/src/api/material/postMaterial';
import {FormProps} from '@/src/interfaces/navbar';
import icons from '@/public/svgs/navbar/prompt';
-const MaterialForm = ({setIsOpen}: FormProps) => {
+const MaterialForm = ({setIsOpen, editData}: FormProps) => {
const inputRef = useRef(null);
const [materialName, setMaterialName] = useState('');
const [material, setMaterial] = useState();
+ useEffect(() => {
+ if (editData) {
+ console.log(editData);
+ }
+ }, []);
+
const handleEnterName = (e: ChangeEvent) => {
setMaterialName(e.target.value);
};
@@ -28,7 +34,7 @@ const MaterialForm = ({setIsOpen}: FormProps) => {
const handleClickButton = () => {
console.log(material, materialName);
if (material && materialName) {
- postMaterial(1, materialName, material);
+ postMaterial(4, materialName, material);
}
};
diff --git a/src/components/navbar/material/MaterialList.tsx b/src/components/navbar/material/MaterialList.tsx
index c8fc3cb..4922cc7 100644
--- a/src/components/navbar/material/MaterialList.tsx
+++ b/src/components/navbar/material/MaterialList.tsx
@@ -10,16 +10,19 @@ import icons from '@/public/svgs/navbar';
const MaterialList = ({
materials,
params,
+ cId,
}: {
materials: Material[];
params: ParamsProps;
+ cId: string | null;
}) => {
const [isToggleOpen, setIsToggleOpen] = useState([]);
const [isOpen, setIsOpen] = useState(false);
+ const [editData, setEditData] = useState();
const handleClickSubject = (mId: number) => {
- if (materials[mId] && materials[mId].prompts.length === 0) {
- postPromptAccess(1, mId);
+ if (materials[mId] && materials[mId].prompts.length === 0 && cId) {
+ postPromptAccess(parseInt(cId), mId);
}
};
@@ -70,6 +73,7 @@ const MaterialList = ({
{
+ setEditData(material);
setIsOpen(true);
setIsToggleOpen(prev => prev.map(() => false));
}}
@@ -89,7 +93,9 @@ const MaterialList = ({
);
})}
- {isOpen ? : null}
+ {isOpen ? (
+
+ ) : null}
);