diff --git a/view/next-project/public/MemberModalFooter.svg b/view/next-project/public/MemberModalFooter.svg new file mode 100644 index 0000000..38ae6dd --- /dev/null +++ b/view/next-project/public/MemberModalFooter.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/view/next-project/public/MemberModalHeader.svg b/view/next-project/public/MemberModalHeader.svg new file mode 100644 index 0000000..5c2ad64 --- /dev/null +++ b/view/next-project/public/MemberModalHeader.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/view/next-project/public/NoUser.svg b/view/next-project/public/NoUser.svg new file mode 100644 index 0000000..c869be2 --- /dev/null +++ b/view/next-project/public/NoUser.svg @@ -0,0 +1,3 @@ + + + diff --git a/view/next-project/src/components/common/BackButton/BackButton.module.css b/view/next-project/src/components/common/BackButton/BackButton.module.css index 5f49827..5a8a4f6 100644 --- a/view/next-project/src/components/common/BackButton/BackButton.module.css +++ b/view/next-project/src/components/common/BackButton/BackButton.module.css @@ -1,4 +1,5 @@ .ButtonContainer { + pointer-events: none; z-index: 10; top: 0; left: 0; @@ -17,6 +18,7 @@ } .ButtonContainer button { + pointer-events: auto; z-index: 10; background: radial-gradient(var(--button-primary), var(--button-secondary)); width: 60px; diff --git a/view/next-project/src/components/common/RecordAddModal/RecordAddModal.tsx b/view/next-project/src/components/common/RecordAddModal/RecordAddModal.tsx index 9810c32..7f95dba 100644 --- a/view/next-project/src/components/common/RecordAddModal/RecordAddModal.tsx +++ b/view/next-project/src/components/common/RecordAddModal/RecordAddModal.tsx @@ -53,8 +53,7 @@ interface CurriculumChapters { } interface Teacher { - user_id: number | string; - record_id: string; + user_id: string; } interface User { @@ -72,7 +71,7 @@ const RecordAddModal: FC = (props) => { const [curriculumChapter, setCurriculumChapter] = useState(); const [records, setRecords] = useState([]); const [users, setUsers] = useState([{ id: '', name: '' }]); - const [teacherData, setTeacherData] = useState({ user_id: 1, record_id: '' }); + const [teacherData, setTeacherData] = useState({ user_id: '1' }); const [isAnimationOpen, setIsAnimationOpen] = useState(false); const [newRecordId, setNewRecordId] = useState(''); @@ -128,8 +127,8 @@ const RecordAddModal: FC = (props) => { ) => { setRecordData({ ...recordData, [input]: e.target.value }); }; - - const handleTeacher = () => (e: React.ChangeEvent) => { + + const handleTeacher = (e: React.ChangeEvent) => { setTeacherData({ ...teacherData, user_id: e.target.value }); }; diff --git a/view/next-project/src/components/common/UserDetailModal/UserDetailModal.module.css b/view/next-project/src/components/common/UserDetailModal/UserDetailModal.module.css new file mode 100644 index 0000000..4065329 --- /dev/null +++ b/view/next-project/src/components/common/UserDetailModal/UserDetailModal.module.css @@ -0,0 +1,298 @@ +.modalContainer { + top: 0; + left: 0; + position: fixed; + padding: 100px; + height: 100vh; + width: 100%; + z-index: 11; + background-color: rgba(51, 51, 51, 0.3); +} + +.modalInnerContainer { + width: 100%; + min-height: 100%; + display: flex; + justify-content: center; + align-items: center; + pointer-events: none; +} + +.modalTakumi { + position: absolute; + width: 50vw; + height: 80vh; +} + +.img_header { + vertical-align:top; + z-index: 30; + position: absolute; + top: 0; + left: 0; + text-align:center; +} + +.img_footer { + vertical-align:top; + z-index: 30; + position: absolute; + right: 0; + bottom: 0; + text-align:center; +} + +.modalContent { + position: absolute; + width: 50vw; + height: 80vh; + display: flex; + flex-flow: column; + padding: 50px 70px 150px 70px; + color: var(--accent-7); + border-radius: var(--card-radius); + background: #FFF9F5; + backdrop-filter: blur(10px); + gap: 30px; + overflow-y: auto; + overscroll-behavior-y: none; + pointer-events:auto; + /*スクロールバー非表示(IE・Edge)*/ + -ms-overflow-style: none; + /*スクロールバー非表示(Firefox)*/ + scrollbar-width: none; +} + +/*スクロールバー非表示(Chrome・Safari)*/ +.modalContent::-webkit-scrollbar{ + display:none; +} + +.contentsTitle { + width: 100%; + display: flex; + justify-content: start; + align-items: start; + flex-flow: row; + flex-wrap: nowrap; +} + +.modalContentContents { + width: 100%; + display: flex; + justify-content: start; + align-items: start; + flex-flow: row; + flex-wrap: nowrap; +} + +.graduationAssignmentMde { + width: 100%; +} + +.graduationAssignmentMde span { + font-size: 16px; + background-color: #fff; +} + +.modalContent input { + font-size: 1.6rem; + width: 100%; + letter-spacing: 1px; + color: var(--accent-6); + background: none; + border: 1px solid var(--accent-4); + padding: 10px; +} + +.modalContent input:focus { + border: 1px solid var(--button-secondary); + z-index: 10; + outline: 0; +} + +.modalContent textarea { + font-size: 1.6rem; + width: 50%; + height: 50rem; + color: var(--accent-6); + background: none; + border: 1px solid var(--accent-4); + padding: 10px; +} + +.modalContent textarea:focus { + border: 1px solid var(--button-secondary); + z-index: 10; + outline: 0; +} + +.modalContent select { + font-size: 1.6rem; + width: 100%; + letter-spacing: 1px; + color: var(--accent-6); + background: none; + border: 1px solid var(--accent-4); + padding: 10px; +} + +.modalContent select:focus { + border: 1px solid var(--button-secondary); + z-index: 10; + outline: 0; +} + +.modalName { + display: flex; + justify-content: center; + align-items: center; +} + +.modalContentClose { + display: flex; + justify-content: start; + align-items: start; +} + +.modalContentCloseIcon { + background: none; + border: none; + margin: -20px; + border-radius: var(--button-radius); + text-align: center; + font-size: 2.8rem; + color: var(--button-secondary); + display: flex; + justify-content: center; + align-items: center; +} + +.modalSubmitButton { + display: flex; + justify-content: center; + align-items: center; +} + +.modalDetail { + margin-top: 50px; +} + +.img { + border-radius: 50%; + width: 180px; + height: 180px; +} + +.wrapper { + display: flex; + justify-content: center +} + +.box1 { + grid-column: 2 / 4; + grid-row: 1; + margin-right:50px; +} + +.box2 { + grid-column: 1; + grid-row: 1 / 3; + display: flex; + flex-direction: column; + justify-content: center; +} + +.username { + border-bottom: solid 2px #000000; + font-size: 40px; + font-weight: bold; +} + +.userrole { + margin-top: 10px; + font-size: 20px; + font-weight: bold; +} + +.userProjects h3 { + font-size: 20px; + font-weight: bold; +} + +.userProjects p { + font-size: 16px; + font-weight: lighter; +} + +.userSkills h3 { + font-size: 20px; + font-weight: bold; +} + +.userSkills p { + font-size: 16px; + font-weight: lighter; +} + +.userRecords h3 { + font-size: 20px; + font-weight: bold; +} + +.userRecords p { + font-size: 16px; + font-weight: lighter; +} + +.box3 { + display: flex; + width: 90%; + margin: 0 auto; + flex-wrap: wrap; +} + +.box4 { + display: flex; + width: 90%; + margin: 0 auto; + flex-wrap: wrap; +} + +.card { + padding: 0.5em 1em; + margin: 0.75em 1rem; + font-weight: bold; + color: #505050; + background: #FFF9F5; + border: solid 4px #FFAC5D; + border-radius: 10px; + display: flex; + justify-content: center; + align-items: center +} + +.card p { + margin: 0; + padding: 0; +} + +.box5 { + width: 86%; + margin: 0 auto; +} + +.record_card { + padding: 0.5em 1em; + margin: 2em 0; + font-weight: bold; + color: #505050; + background: #FFF9F5; + border-bottom: dashed 2px #FFAC5D; + width: 100%; +} + +.record_card p { + margin: 0; + padding: 0; +} \ No newline at end of file diff --git a/view/next-project/src/components/common/UserDetailModal/UserDetailModal.tsx b/view/next-project/src/components/common/UserDetailModal/UserDetailModal.tsx new file mode 100644 index 0000000..e162cac --- /dev/null +++ b/view/next-project/src/components/common/UserDetailModal/UserDetailModal.tsx @@ -0,0 +1,146 @@ +import React from 'react'; +import s from './UserDetailModal.module.css'; + +interface User { + id: number; + provider: string; + uid: string; + allow_password_change: boolean; + name: string; + email: string; + created_at: string; + updated_at: string; +}; + +interface Type { + id: string; + name: string; + created_at: string; + updated_at: string; +}; + +interface UserDetail { + icon_name: string; + github: string; + slack: string; + biography: string; + pc_name: string; + pc_os: string; + pc_cpu: string; + pc_ram: string; + pc_storage: string; + type: Type; +}; + +interface Project { + id: number; + project: string; + role: string; +}; + +interface Record { + id: number; + title: string; + teacher: User; +}; + +interface Skill { + id: number; + name: string; + category: string; +}; + +interface UserDetailModalProps { + onClose: () => void; + user: User; + userDetail: UserDetail; + userProject?: Project[] | null; + userSkill?: Skill[] | null; + userRecord?: Record[] | null; +}; + +const UserDetailModal: React.FC = (props) => { + const { user, userDetail, userProject, userSkill, userRecord } = props; + + const handleOutsideClick = (e: React.MouseEvent) => { + if (e.target === e.currentTarget) { + props.onClose(); + } + }; + + return ( +
+ +
+ +
+ + + +
+ +
+ +
+
+ +
+
+

{user.name}

+

{userDetail.type.name}

+
+
+ + {userProject && ( +
+

Projects

+
+ {userProject.map(project => ( +
+

{project.project}

+
+ ))} +
+
+ )} + + {userSkill && ( +
+

Skills

+
+ {userSkill.map(skill => ( +
+

{skill.name}

+
+ ))} +
+
+ )} + + {userRecord && ( +
+

Records

+
+ {userRecord.map(record => ( +
+

{record.title}

+
+ ))} +
+
+ )} +
+ +
+ + + +
+ +
+ +
+ ); +} + +export default UserDetailModal; diff --git a/view/next-project/src/components/common/UserDetailModal/index.ts b/view/next-project/src/components/common/UserDetailModal/index.ts new file mode 100644 index 0000000..2c75cc4 --- /dev/null +++ b/view/next-project/src/components/common/UserDetailModal/index.ts @@ -0,0 +1 @@ +export { default } from './UserDetailModal' \ No newline at end of file diff --git a/view/next-project/src/pages/users/index.tsx b/view/next-project/src/pages/users/index.tsx index de708c4..bb0cec2 100644 --- a/view/next-project/src/pages/users/index.tsx +++ b/view/next-project/src/pages/users/index.tsx @@ -5,16 +5,37 @@ import styled from 'styled-components'; import AccountCircle from '@components/icons/AccountCircle'; import UserBackgroundAnimation from '@components/common/UsersBackgroundAnimation/UsersBackgroundAnimation'; import MemberSearchButton from '@components/common/MemberSearchButton'; - +import React, { useState } from 'react'; +import OpenUserDetailModal from '@components/common/UserDetailModal/UserDetailModal'; interface Props { userDetails: UserDetails[]; } - interface UserDetails { user: User; detail: UserDetail; + type: Type; + projects: Project[]; + records: Record[]; + skills: Skill[]; +} + +interface Project { + id: number; + project: string; + role: string; } +interface Record { + id: number; + title: string; + teacher: User; +} + +interface Skill { + id: number; + name: string; + category: string; +} interface User { id: number; provider: string; @@ -25,35 +46,30 @@ interface User { created_at: string; updated_at: string; } - interface Grade { id: string; name: string; created_at: string; updated_at: string; } - interface Department { id: string; name: string; created_at: string; updated_at: string; } - interface Bureau { id: string; name: string; created_at: string; updated_at: string; } - interface Type { id: string; name: string; created_at: string; updated_at: string; } - interface UserDetail { grade: Grade; department: Department; @@ -69,9 +85,8 @@ interface UserDetail { pc_storage: string; type: Type; } - export async function getServerSideProps() { - const getUrl = process.env.SSR_API_URI + '/api/v1/get_users_for_user_page'; + const getUrl = process.env.SSR_API_URI + '/api/v1/get_users_for_member_page'; const json = await get(getUrl); return { props: { @@ -79,10 +94,8 @@ export async function getServerSideProps() { }, }; } - export default function UserList(props: Props) { const accountCircleColor = '#636363'; - const UserListContainer = styled.div` display: flex; flex-wrap: wrap; @@ -165,7 +178,6 @@ export default function UserList(props: Props) { z-index: 2; display: flex; `; - const MemberPageTitle = styled.div` position: fixed; top: 11%; @@ -179,7 +191,6 @@ export default function UserList(props: Props) { color: #ffffff; text-align: center; `; - const TopSearchButton = styled.div` position: fixed; top: 15%; @@ -194,8 +205,28 @@ export default function UserList(props: Props) { transform: translate(-50%, -50%); z-index: 9; `; - const router = useRouter(); + const [isOpenUserDetailModal, setIsOpenUserDetailModal] = useState(false); + const [currentUser, setCurrentUser] = useState(null); + const [currentDetail, setCurrentDetail] = useState(null); + const [currentProjects, setCurrentProjects] = useState(null); + const [currentRecords, setCurrentRecords] = useState(null); + const [currentSkills, setCurrentSkills] = useState(null); + const onOpen = () => { + setIsOpenUserDetailModal(true); + }; + const onClose = () => { + setIsOpenUserDetailModal(false); + }; + + const handleCardClick = (userDetail: UserDetails) => { + setCurrentUser(userDetail.user); + setCurrentDetail(userDetail.detail); + setCurrentProjects(userDetail.projects); + setCurrentRecords(userDetail.records); + setCurrentSkills(userDetail.skills); + setIsOpenUserDetailModal(true); + }; const userContent = (userDetail: any) => { return ( @@ -211,7 +242,6 @@ export default function UserList(props: Props) { - {userDetail.user.name ? userDetail.user.name : ''} {userDetail.detail.type.name ? userDetail.detail.type.name : ''} @@ -222,7 +252,6 @@ export default function UserList(props: Props) { ); }; - return ( Members @@ -234,11 +263,13 @@ export default function UserList(props: Props) { {props.userDetails.map((userDetail) => ( -
router.push(`users/${userDetail.user.id}`)}> +
handleCardClick(userDetail)}> {userContent(userDetail)}
))} + {isOpenUserDetailModal && currentUser && currentDetail && + }