Skip to content

Commit

Permalink
♻️ refactor : Remove duplicate code from the card component
Browse files Browse the repository at this point in the history
- Unify card components that maintain the same style
- Manage many props at once with interface files

Related Issue : YJU-OKURA#59
  • Loading branch information
Lainari committed Apr 21, 2024
1 parent 9b57abd commit 4cc5b2c
Show file tree
Hide file tree
Showing 13 changed files with 142 additions and 117 deletions.
17 changes: 0 additions & 17 deletions src/app/components/_class/Created.tsx

This file was deleted.

17 changes: 0 additions & 17 deletions src/app/components/_class/Favorite.tsx

This file was deleted.

27 changes: 20 additions & 7 deletions src/app/components/_class/Invite.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,27 @@ import {Invitation} from '../card';
import logos from '@/public/images/_class';
import {InviteProps} from '@/src/interfaces/_class';

const Invite = ({onInvitationClick}: InviteProps) => {
const Invite = ({onInvitationClick, classes = []}: InviteProps) => {
return (
<Invitation
ImageSrc={logos.github}
ClassName={'Github'}
ManagerName={'TenJinseok'}
onClick={onInvitationClick}
/>
<>
{classes &&
classes.map(classItem => (
<div key={classItem.id}>
<Invitation
ImageSrc={classItem.image}
ClassName={classItem.name}
ManagerName={'TEST'}
onClick={onInvitationClick}
/>
</div>
))}
<Invitation
ImageSrc={logos.github}
ClassName={'Github'}
ManagerName={'TenJinseok'}
onClick={onInvitationClick}
/>
</>
);
};

Expand Down
25 changes: 0 additions & 25 deletions src/app/components/_class/Joined.tsx

This file was deleted.

67 changes: 53 additions & 14 deletions src/app/components/_class/Main.tsx
Original file line number Diff line number Diff line change
@@ -1,41 +1,77 @@
'use client';

import React, {useEffect, useState} from 'react';
import {Favorite, Created, Joined, Invite, Waiting, Header} from '.';
import {Invite, Waiting, Header} from '.';
import {ClassCreate, ClassJoin, ClassPassword} from './modal';
import {CardList} from '../card';
import {Dashboard, TabsMapping} from '@/src/components/dashboard';
import User from '@/src/model/User';
import getClasses from '@/src/api/_class/getClasses';
import classAPI from '@/src/api/_class';

const Main = () => {
const [classes, setClasses] = useState([]);
const tabs = ['Joined', 'Created', 'Favorite', 'Invite', 'Waiting'];
const [classes, setClasses] = useState([]);
const [createdClasses, setCreatedClasses] = useState([]);
const [inviteClasses, setInviteClasses] = useState([]);
const [favoriteClasses, setFavoriteClasses] = useState([]);
const [waitingClasses, setWaitingClasses] = useState([]);
const [activeTab, setActiveTab] = useState(tabs[0]);
const [activeModalId, setActiveModalId] = useState('');
const [isModalOpen, setIsModalOpen] = useState(false);

const getClassAfterCreate = async () => {
const allRes = await classAPI.getClasses(User.uid);
setClasses(allRes.data);
};

useEffect(() => {
const loadClasses = async () => {
const response = await getClasses(User.uid);
setClasses(response.data);
switch (activeTab) {
case 'Created': {
const createdRes = await classAPI.getClassesRole(User.uid, 2);
setCreatedClasses(createdRes.data);
break;
}
case 'Invite': {
const inviteRes = await classAPI.getClassesRole(User.uid, 6);
setInviteClasses(inviteRes.data);
break;
}
case 'Waiting': {
const waitingRes = await classAPI.getClassesRole(User.uid, 4);
setWaitingClasses(waitingRes.data);
break;
}
case 'Favorite': {
const favoriteRes = await classAPI.getFavoriteClasses(User.uid);
setFavoriteClasses(favoriteRes.data);
break;
}
default: {
const allRes = await classAPI.getClasses(User.uid);
setClasses(allRes.data);
break;
}
}
};

loadClasses();
}, []);
}, [activeTab]);

const handleModalOpen = () => {
setIsModalOpen(true);
};
const handleModalClose = () => {
setIsModalOpen(false);
};

const tabMapping = {
Joined: <Joined classes={classes} />,
// {/* バックエンドAPIの修正が終わったら、四つのComponentも追加します。 */}
Created: <Created />,
Favorite: <Favorite />,
Invite: <Invite onInvitationClick={handleModalOpen} />,
Waiting: <Waiting />,
Joined: <CardList classes={classes} />,
Created: <CardList classes={createdClasses} />,
Favorite: <CardList classes={favoriteClasses} />,
Invite: (
<Invite onInvitationClick={handleModalOpen} classes={inviteClasses} />
),
Waiting: <Waiting classes={waitingClasses} />,
};

return (
Expand All @@ -51,7 +87,10 @@ const Main = () => {
<TabsMapping activeTab={activeTab} tabMapping={tabMapping} />
</div>
{activeModalId === 'classCreate' && (
<ClassCreate setActiveModalId={setActiveModalId} />
<ClassCreate
setActiveModalId={setActiveModalId}
getClassAfterCreate={getClassAfterCreate}
/>
)}
{activeModalId === 'classJoin' && (
<ClassJoin
Expand Down
25 changes: 12 additions & 13 deletions src/app/components/_class/Waiting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,23 @@

import {useState} from 'react';
import {ClassWait} from './modal';
import {Card} from '../card';
import {ClassProps} from '@/src/interfaces/_class';
import logos from '@/public/images/_class';

const Waiting = () => {
const Waiting = ({classes}: ClassProps) => {
const [modalOpen, setModalOpen] = useState(false);
const handleModalOpen = () => {
setModalOpen(true);
};
return (
<>
<div onClick={handleModalOpen}>
<Card
ImageSrc={logos.wasedauni}
ClassName={'Waseda University'}
ClassContent={'Independence of Learning'}
disableLink={true}
/>
</div>
{classes &&
classes.map(classItem => (
<div key={classItem.id}>
<ClassWait
ImageSrc={classItem.image}
ClassName={classItem.name}
setIsModalOpen={setModalOpen}
/>
</div>
))}
{modalOpen && (
<ClassWait
ImageSrc={logos.wasedauni}
Expand Down
5 changes: 1 addition & 4 deletions src/app/components/_class/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import Created from './Created';
import Favorite from './Favorite';
import Header from './Header';
import Invite from './Invite';
import Joined from './Joined';
import Main from './Main';
import Waiting from './Waiting';

export {Created, Favorite, Header, Invite, Joined, Main, Waiting};
export {Header, Invite, Main, Waiting};
32 changes: 17 additions & 15 deletions src/app/components/card/Card.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
'use client';
import Image from 'next/image';
import Link from 'next/link';
import {CardProps} from '@/src/interfaces/_class';
import {CardItemProps} from '@/src/interfaces/_class';
import icons from '@/public/svgs/_class';
import logos from '@/public/images/_class';

const Card = ({
ImageSrc,
ClassName,
ClassContent,
FavoriteChecked,
disableLink,
}: CardProps) => {
const Card: React.FC<CardItemProps> = ({classData}) => {
const cardContent = (
<>
<div className="border rounded-lg w-80 h-72 border-gray-300 mr-10 mb-10 hover:shadow-md active:bg-neutral-50 focus:ring focus:ring-gray-400 transform hover:scale-105 transition duration-200 ease-in-out">
<div className="flex justify-center items-center mt-2">
<div className="w-72 h-44 relative overflow-hidden">
<Image
src={logos.yeungjin || ImageSrc}
src={classData.ImageSrc || logos.yeungjin}
alt={'Card Image'}
fill={true}
sizes="(max-width: 288px), (max-hight:176px)"
Expand All @@ -27,10 +21,10 @@ const Card = ({
</div>
</div>
<div className="flex place-content-between ms-4 mt-2">
<h3 className="font-bold text-lg">{ClassName}</h3>
{disableLink ? null : (
<h3 className="font-bold text-lg">{classData.ClassName}</h3>
{classData.disableLink ? null : (
<>
{FavoriteChecked ? (
{classData.FavoriteChecked ? (
<Image
src={icons.favorite}
alt="favoriteChecked"
Expand All @@ -51,17 +45,25 @@ const Card = ({
)}
</div>
<p className="text-base ms-4 mt-2 me-2 overflow-hidden overflow-ellipsis whitespace-nowrap">
{ClassContent}
{classData.ClassContent}
</p>
</div>
</>
);

return (
<>
{disableLink ? (
{classData.disableLink ? (
cardContent
) : (
<Link href={`/${ClassName}`}>{cardContent}</Link>
<Link
href={{
pathname: `/${classData.ClassName}`,
query: {id: `${classData.ClassId}`},
}}
>
{cardContent}
</Link>
)}
</>
);
Expand Down
26 changes: 26 additions & 0 deletions src/app/components/card/CardList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {Card} from '../card';
import {ClassProps} from '@/src/interfaces/_class';

const CardList = ({classes}: ClassProps) => {
return (
<>
{classes.map(classItem => {
const classData = {
ImageSrc: classItem.image,
ClassName: classItem.name,
ClassContent: classItem.description,
FavoriteChecked: classItem.is_favorite,
ClassId: classItem.id,
};

return (
<div key={classItem.id}>
<Card classData={classData} />
</div>
);
})}
</>
);
};

export default CardList;
3 changes: 2 additions & 1 deletion src/app/components/card/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Card from './Card';
import CardList from './CardList';
import Invitation from './Invitation';

export {Card, Invitation};
export {Card, CardList, Invitation};
7 changes: 6 additions & 1 deletion src/interfaces/_class/cardProps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ interface CardProps {
ClassContent: string;
FavoriteChecked?: boolean;
disableLink?: boolean;
ClassId?: number;
}

export default CardProps;
interface CardItemProps {
classData: CardProps;
}

export default CardItemProps;
4 changes: 2 additions & 2 deletions src/interfaces/_class/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import InvitationProps from './invitationProps';
import CardProps from './cardProps';
import CardItemProps from './cardProps';
import DropdownProps from './dropdownProps';
import ScheduleCardProps from './scheduleCardProps';
import PostCardProps from './postCardProps';
Expand All @@ -9,7 +9,7 @@ import ClassProps from './classProps';

export type {
InvitationProps,
CardProps,
CardItemProps,
DropdownProps,
ScheduleCardProps,
PostCardProps,
Expand Down
4 changes: 3 additions & 1 deletion src/interfaces/_class/inviteProps.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
interface InviteProps {
import ClassProps from './classProps';
interface InviteProps extends ClassProps {
onInvitationClick: () => void;
classes: ClassProps['classes'];
}

export default InviteProps;

0 comments on commit 4cc5b2c

Please sign in to comment.