Skip to content

Commit

Permalink
Merge pull request #198 from GSM-MSG/feature/owner-transfer
Browse files Browse the repository at this point in the history
🔀 서비스 소유자 위임 기능 추가
  • Loading branch information
SeoJumee authored Mar 11, 2024
2 parents e632b8a + 0da9ef2 commit 6e0db4e
Show file tree
Hide file tree
Showing 16 changed files with 413 additions and 12 deletions.
18 changes: 18 additions & 0 deletions public/svg/XIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export default function XIcon() {
return (
<svg
width="18"
height="18"
viewBox="0 0 18 18"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M4.05161 2.63604C3.66109 2.24551 3.02792 2.24551 2.6374 2.63604C2.24687 3.02656 2.24687 3.65973 2.6374 4.05025L7.58749 9.00035L2.63775 13.9501C2.24722 14.3406 2.24722 14.9738 2.63775 15.3643C3.02827 15.7548 3.66143 15.7548 4.05196 15.3643L9.00171 10.4146L13.952 15.3648C14.3425 15.7553 14.9757 15.7553 15.3662 15.3648C15.7567 14.9743 15.7567 14.3411 15.3662 13.9506L10.4159 9.00035L15.3657 4.0506C15.7562 3.66008 15.7562 3.02691 15.3657 2.63639C14.9751 2.24586 14.342 2.24586 13.9515 2.63639L9.00171 7.58613L4.05161 2.63604Z"
fill="#929292"
/>
</svg>
);
}
1 change: 1 addition & 0 deletions public/svg/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ export * from './ServicePublic';
export * from './ServicePrivate';
export * from './AddServiceImg';
export * from './DeleteServiceImg';
export * from './XIcon';
12 changes: 12 additions & 0 deletions src/Atom/Atoms.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
} from '../types';
import { StuListType } from '../types/StuListType';
import { StulistFilterType } from '../types/StulistFilterType';
import { ServiceOwnerModalType } from '../types/components/ServiceOwnerModalType';

export const ViewWidth = atom<number>({
key: 'viewWidth',
Expand All @@ -16,6 +17,7 @@ export const ViewWidth = atom<number>({
export const User = atom<ClientInform>({
key: 'user',
default: {
userId: 0,
email: '',
name: '',
grade: 0,
Expand Down Expand Up @@ -93,3 +95,13 @@ export const ServiceCheckList = atom<ClientListType[]>({
key: 'serviceCheckList',
default: [],
});

export const ServiceOwnerModal = atom<ServiceOwnerModalType>({
key: 'ServiceOwnerModal',
default: '',
});

export const ServiceOwnerUserId = atom<number>({
key: 'serviceOwnerUserId',
default: 0,
});
4 changes: 2 additions & 2 deletions src/components/MyProfilePage/Profile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ export default function Profile() {
<h1>{user.name}</h1>
<p>
{!user.grade && !user.classNum && !user.number
? '졸업생'
: `${user.grade}학년 ${user.classNum}${user.number}번`}
? '졸업생'
: `${user.grade}학년 ${user.classNum}${user.number}번`}
</p>
<h3>{user.email}</h3>
</S.PrivacySection>
Expand Down
29 changes: 27 additions & 2 deletions src/components/MyServiceList/Modify/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,17 @@ import { useEffect, useState } from 'react';
import { FieldValues, useForm } from 'react-hook-form';
import * as SVG from '../../../../public/svg';
import { toast } from 'react-toastify';
import { useUser } from '../../../hooks/useUser';
import Input from '../../common/Input';
import * as S from './style';
import useFetch from '../../../hooks/useFetch';
import { ResNewService } from '../../../types/ResAddService';
import Image from 'next/image';
import { useRouter } from 'next/router';
import { Search, ServiceOwnerModal } from '../../../Atom/Atoms';
import { useRecoilState, useSetRecoilState } from 'recoil';
import ServiceOwnerList from '../../ServiceOwnerList';
import Assignment from '../../ServiceOwnerList/Assignment';
import { useUser } from '../../../hooks/useUser';

export default function ModifyMyService({ modifyId }: { modifyId: string }) {
const {
Expand All @@ -19,11 +23,14 @@ export default function ModifyMyService({ modifyId }: { modifyId: string }) {
handleSubmit,
} = useForm();

const [user, getUser] = useUser(true);
const [serviceScope, setServiceScope] = useState<string>('');
const regUri = /^(http(s)?:\/\/|www.)([a-z0-9\w]+\.*)+[a-z0-9]{2,4}/gi;
const [serviceImgUrl, setServiceImgUrl] = useState('');
const router = useRouter();
const [serviceOwnerModal, setServiceOwnerModal] =
useRecoilState(ServiceOwnerModal);
const setSearch = useSetRecoilState(Search);
const [user, getUser] = useUser();

const { fetch: getService } = useFetch<ResNewService>({
url: `/client/${modifyId}`,
Expand Down Expand Up @@ -96,6 +103,20 @@ export default function ModifyMyService({ modifyId }: { modifyId: string }) {
onSuccess: () => setServiceImgUrl(''),
});

const closeModal = () => {
setServiceOwnerModal('');
setSearch('');
};

const renderModalContent = () => {
switch (serviceOwnerModal) {
case 'list':
return <ServiceOwnerList userId={user.userId} onClose={closeModal} />;
case 'assignment':
return <Assignment onClose={closeModal} modifyId={modifyId} />;
}
};

return (
<S.Container>
<S.Wrapper>
Expand Down Expand Up @@ -245,6 +266,10 @@ export default function ModifyMyService({ modifyId }: { modifyId: string }) {
</S.Section>
</S.SectionWrapper>
<S.Border />
<S.OwnerButton onClick={() => setServiceOwnerModal('list')}>
소유자 이전하기
</S.OwnerButton>
{serviceOwnerModal && renderModalContent()}
</S.Wrapper>
</S.Container>
);
Expand Down
11 changes: 11 additions & 0 deletions src/components/MyServiceList/Modify/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -270,3 +270,14 @@ export const Scope = styled.div`
cursor: pointer;
}
`;

export const OwnerButton = styled.button`
width: 125px;
height: 40px;
cursor: pointer;
background: none;
border: 1px solid #e0e0e0;
border-radius: 10px;
color: #8c8c8c;
font-size: 16px;
`;
53 changes: 53 additions & 0 deletions src/components/ServiceOwnerList/Assignment/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { useRouter } from 'next/router';
import { useRecoilState, useRecoilValue } from 'recoil';
import { ErrorIcon } from '../../../../public/svg';
import { ServiceOwnerUserId } from '../../../Atom/Atoms';
import useFetch from '../../../hooks/useFetch';
import Portal from '../../common/Portal';
import * as S from './style';

interface Props {
onClose: () => void;
modifyId: string;
}

export default function Assignment({ onClose, modifyId }: Props) {
const [serviceOwnerUserId, setServiceOwnerUserId] =
useRecoilState(ServiceOwnerUserId);
const router = useRouter();

const { fetch } = useFetch({
url: `client/${modifyId}/owner?userId=${serviceOwnerUserId}`,
method: 'patch',
onSuccess: () => {
setServiceOwnerUserId(0);
onClose();
router.push('/myprofile');
},
});

return (
<Portal onClose={onClose}>
<S.Wrapper>
<h1>소유자 권한 양도</h1>
<div>
<S.Title>
<ErrorIcon />
<div>
<h4>정말 소유자 권한을 양도하실 건가요?</h4>
<p>소유자 권한을 양도하면 모든 권한을 양도하게 됩니다.</p>
</div>
</S.Title>
<S.ButtonWrapper>
<S.Button modeType onClick={() => fetch()}>
양도
</S.Button>
<S.Button modeType={false} onClick={onClose}>
취소
</S.Button>
</S.ButtonWrapper>
</div>
</S.Wrapper>
</Portal>
);
}
86 changes: 86 additions & 0 deletions src/components/ServiceOwnerList/Assignment/style.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import styled from '@emotion/styled';

export const Wrapper = styled.div`
width: 426px;
aspect-ratio: auto 1 / 1.319;
background: #ffffff;
border-radius: 10px;
padding: 50px 40px 40px;
display: flex;
flex-direction: column;
text-align: center;
font-size: 20px;
> h1 {
font-weight: 600;
font-size: 1.2em;
}
> div {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
}
@media (max-width: 550px) {
width: 78vw;
font-size: 3.6364vw;
padding: 9vw 40px 40px;
}
`;

export const Title = styled.div`
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
gap: 20px;
svg {
width: 5.4em;
height: 5.4em;
}
h4 {
font-weight: 600;
font-size: 0.8em;
color: #1c1c1c;
}
p {
margin-top: 6px;
margin-right: 3px;
font-weight: 500;
font-size: 0.65em;
color: #929292;
}
`;

export const ButtonWrapper = styled.div`
width: 100%;
aspect-ratio: auto 1 / 0.125;
display: flex;
justify-content: space-between;
gap: 10px;
`;

export const Button = styled.button`
width: 100%;
font-weight: 500;
font-size: 0.65em;
border-radius: 10px;
cursor: pointer;
opacity: 0.8;
transition: 0.4s;
background: ${({ modeType }: { modeType: boolean }) =>
modeType ? '#DE4949' : '#D1D1D1'};
color: ${({ modeType }: { modeType: boolean }) =>
modeType ? '#FFFFFF' : '#888888'};
:hover {
opacity: 1;
}
`;
81 changes: 81 additions & 0 deletions src/components/ServiceOwnerList/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { useEffect } from 'react';
import { useRecoilValue, useSetRecoilState } from 'recoil';
import XIcon from '../../../public/svg/XIcon';
import {
Search,
ServiceOwnerUserId,
ServiceOwnerModal,
StuList,
} from '../../Atom/Atoms';
import { useUserList } from '../../hooks/useUserList';
import Portal from '../common/Portal';
import SearchBar from '../common/SearchBar';
import * as S from './style';

interface Props {
onClose: () => void;
userId: number;
}

export default function ServiceOwnerList({ onClose, userId }: Props) {
const setServiceOwnerModal = useSetRecoilState(ServiceOwnerModal);
const search = useRecoilValue(Search);
const stuList = useRecoilValue(StuList);
const setServiceOwnerUserId = useSetRecoilState(ServiceOwnerUserId);

const { getUserList } = useUserList({
defaultUri: `/user/user-list?grade=0&classNum=0&keyword=&role=ROLE_STUDENT`,
});

useEffect(() => {
getUserList();
}, []);

return (
<Portal onClose={onClose}>
<S.Container>
<S.TitleWrapper>
<h1>소유자 이전</h1>
<div onClick={onClose}>
<XIcon />
</div>
</S.TitleWrapper>
<SearchBar placeholder="이름으로 검색하기..." />
<S.TableWrapper>
<S.Table>
<thead>
<tr>
<th>이름</th>
<th>학년</th>
<th></th>
<th>번호</th>
</tr>
</thead>
<tbody>
{stuList
.filter((e) => e.name?.includes(search) && e.id !== userId)
.map((e, idx) => (
<tr key={idx}>
<td>{e.name}</td>
<td>{e.grade}</td>
<td>{e.classNum}</td>
<td>{e.num}</td>
<td>
<button
onClick={() => {
setServiceOwnerModal('assignment');
setServiceOwnerUserId(e.id);
}}
>
권한 양도
</button>
</td>
</tr>
))}
</tbody>
</S.Table>
</S.TableWrapper>
</S.Container>
</Portal>
);
}
Loading

0 comments on commit 6e0db4e

Please sign in to comment.