jaehyuk-jang

Intergrated views for webpages

//@ts-nocheck
import React from 'react';
import { Table as TableContainer, TableProps } from 'antd';
import { useWindowSize } from '@src/hooks';
import TableHeader from './TableHeader';
interface NewTableProps extends TableProps<any> {
title: string;
columns: Object[];
data: Object[];
}
export default function Table({
title,
columns,
data,
...rest
}: NewTableProps) {
const [width, height] = useWindowSize();
const size = width > 1000 ? 'middle' : 'small';
const cellHeight = size === 'small' ? 39 : 55;
const pageSize = Math.ceil((height * 2) / 3 / cellHeight);
const emptyRowNum = pageSize - (data.length % pageSize);
const emptyRow = columns.reduce(
(acc, curr) => ((acc[curr['dataIndex']] = '-'), acc),
{},
);
const body = [...data, ...Array(emptyRowNum || 0).fill(emptyRow)];
return (
<TableContainer
size={size}
title={() => <TableHeader title={title} />}
columns={columns}
dataSource={body}
pagination={{
responsive: true,
showLessItems: true,
pageSize,
}}
{...rest}
/>
);
}
import React from 'react';
import { Button } from 'antd';
import Link from 'next/link';
import { useRouter } from 'next/router';
export default function TableHeader({ title }) {
const { query } = useRouter();
return (
<div className={'ant-table-title'}>
<h2>{title} 게시판</h2>
<Button>
<Link href={`/${query.name}/create`}>{'글쓰기'}</Link>
</Button>
</div>
);
}
import Table from './Table';
import {
makeArticleURLWithNumber,
makeCategoryTableBody,
} from '@shared/functions';
import { useRouter } from 'next/router';
export default function Category({ category, articleList }) {
const router = useRouter();
// example
const newData = makeCategoryTableBody(articleList);
const handleRoute = ({ id }) => (e) => {
e.preventDefault();
if (id === '-') return;
const {
query: { name: categoryName },
} = router;
const URL = makeArticleURLWithNumber(categoryName as string, id);
router.push(URL);
};
return (
<div className={'outer-container category-table-container'}>
<Table
title={category}
columns={[
{
key: '1',
title: 'No.',
dataIndex: 'id',
align: 'center',
},
{ key: '2', title: '제목', dataIndex: 'title', width: '70%' },
{
key: '3',
title: '작성자',
dataIndex: 'author',
align: 'center',
},
{
key: '4',
title: '등록일',
dataIndex: 'created_date',
align: 'center',
},
]}
data={newData}
onRow={(record) => ({
onClick: handleRoute(record),
})}
/>
</div>
);
}
import React from 'react';
import { Button } from 'antd';
export default function Buttons({ buttons }) {
return (
<div>
{buttons.map(({ title, ...rest }) => (
<Button key={title} {...rest}>
{title}
</Button>
))}
</div>
);
}
import React from 'react';
import { Form } from 'antd';
export default function Inputs({ forms }) {
return (
<>
{forms.map(({ form, input: { Item, value, ...rest } }) => (
<Form.Item {...form} required key={value}>
<Item placeholder={value} name={value} {...rest} />
</Form.Item>
))}
</>
);
}
export { default as CreateInputs } from './Inputs';
export { default as CreateButtons } from './Buttons';
import Link from 'next/link';
import { Card as CardItem } from 'antd';
import { Row } from './Row';
function MoreButton(category) {
return <Link href={`/category/${category}`}>더보기</Link>;
}
export default function Card({ category, posts, ...rest }) {
const postsNum = posts.length;
const emptyRows = postsNum < 5 ? Array(5 - postsNum).fill(null) : [];
const sliced = postsNum > 5 ? posts.slice(postsNum - 5, postsNum) : posts;
return (
<CardItem title={category} extra={MoreButton(category)} {...rest}>
{sliced.map(({ title, id }) => (
<Row key={title} category={category} title={title} id={id} />
))}
{emptyRows.map((_, idx) => (
<div className={'card-row'} key={idx} />
))}
</CardItem>
);
}
import { useRouter } from 'next/router';
import { makeArticleURLWithNumber } from '@src/shared/functions';
export const Row = ({ category, title, id }) => {
const router = useRouter();
const sliced = title.length > 20 ? title.substr(0, 20) + '...' : title;
const handleClickArticle = () => {
const URL = makeArticleURLWithNumber(category, id);
router.push(URL);
};
return (
<div className={'card-row has-content'} onClick={handleClickArticle}>
<h2 className={'card-row-title'}>{sliced}</h2>
<span className={'card-row-recomment'}>{'?'}</span>
</div>
);
};
import Card from '@src/views/Main/Card';
export default function Main({ categories, posts }) {
return (
<div className={'outer-container main-card-container'}>
{categories?.map((category) => {
const filtered = posts.filter((post) => post.category === category);
return (
<Card
key={category}
category={category}
posts={filtered}
className={'main-card'}
/>
);
})}
</div>
);
}
import React, { useState } from 'react';
import { Comment as CommentItem, Divider } from 'antd';
import Profile from './Profile';
import Datetime from './Datetime';
import Like from './Like';
import Dislike from './Dislike';
export default function Comment({
author,
content,
created_date,
idx,
commentsNum,
}) {
const [likes, setLikes] = useState(0);
const [dislikes, setDislikes] = useState(0);
const [action, setAction] = useState(null);
const like = () => {
setLikes(1);
setDislikes(0);
setAction('liked');
};
const dislike = () => {
setLikes(0);
setDislikes(1);
setAction('disliked');
};
return (
<>
<CommentItem
actions={[
Like({ action, like, likes }),
Dislike({
action,
dislike,
dislikes,
}),
]}
author={<a>{author}</a>}
avatar={Profile({ src: '', author })}
content={<div dangerouslySetInnerHTML={{ __html: content }} />}
datetime={Datetime({ created_date })}
/>
{commentsNum - 1 !== idx && <Divider />}
</>
);
}
import React from 'react';
import { Tooltip } from 'antd';
import moment from 'moment';
export default function Datetime({ created_date }) {
return (
<Tooltip title={moment(created_date).format('YYYY-MM-DD HH:mm:ss')}>
<span>{moment(created_date).fromNow()}</span>
</Tooltip>
);
}
import React, { createElement } from 'react';
import { Tooltip } from 'antd';
import { DislikeOutlined, DislikeFilled } from '@ant-design/icons';
export default function Dislike({ dislike, action, dislikes }) {
return (
<Tooltip key="comment-basic-dislike" title="Dislike">
<span onClick={dislike}>
{createElement(action === 'disliked' ? DislikeFilled : DislikeOutlined)}
<span className="comment-action">{dislikes}</span>
</span>
</Tooltip>
);
}
import React, { createElement } from 'react';
import { Tooltip } from 'antd';
import { LikeOutlined, LikeFilled } from '@ant-design/icons';
export default function Like({ action, like, likes }) {
return (
<Tooltip key="comment-basic-like" title="Like">
<span onClick={like}>
{createElement(action === 'liked' ? LikeFilled : LikeOutlined)}
<span className="comment-action">{likes}</span>
</span>
</Tooltip>
);
}
import React from 'react';
import { Avatar } from 'antd';
export default function Profile({ src, author }) {
return (
<Avatar
src={
src
? src
: 'https://zos.alipayobjects.com/rmsportal/ODTLcjxAfvqbxHnVXCYX.png'
}
alt={author}
/>
);
}
import React from 'react';
import TextArea from 'antd/lib/input/TextArea';
import { Button } from 'antd';
import { useMutation } from '@apollo/client';
import { CREATE_COMMENT } from '@src/gql/create-comment';
export default function Submit({ title, postId, addCommentList }) {
const [content, setContent] = React.useState('');
const [createComment] = useMutation(CREATE_COMMENT);
const handleChange = (e) => {
setContent(e.target.value);
};
const handleSubmit = async () => {
const { data } = await createComment({
variables: { input: { content, post_id: postId } },
});
setContent('');
data && addCommentList(data.createComment);
};
return (
<>
<TextArea
value={content}
onChange={handleChange}
placeholder={'댓글을 입력하세요'}
autoSize={{ minRows: 3, maxRows: 5 }}
className={'comments-textarea'}
/>
<Button
type={'primary'}
size={'large'}
onClick={handleSubmit}
className={'comments-submit-button'}
>
{title}
</Button>
</>
);
}
import React, { useState } from 'react';
import { Card } from 'antd';
import Submit from './Submit';
import Comment from './Comment';
export default function CommentsContainer({ comments, postId }) {
const [tempComments, setTempComments] = useState(comments);
const commentsNum = tempComments?.length;
const addCommentList = (data) => {
setTempComments((prev) => [...prev, data]);
};
React.useEffect(() => {
comments && setTempComments(comments);
}, [comments]);
return (
<Card className={'post-comments'}>
<h1 className={'post-comments-num'}>{`COMMENTS (${commentsNum})`}</h1>
{tempComments?.map(({ author, content, created_date }, idx) => (
<Comment
key={created_date}
author={author}
content={content}
created_date={created_date}
idx={idx}
commentsNum={commentsNum}
/>
))}
<Submit title={'작성'} postId={postId} addCommentList={addCommentList} />
</Card>
);
}
import React from 'react';
import { Card, Descriptions } from 'antd';
import moment from 'moment';
export default function Content({
id,
author,
category,
created_date,
title,
content,
}) {
return (
<Card className={'post-content'}>
<Descriptions title={title} layout={'horizontal'} column={3}>
<Descriptions.Item label={'작성자'} span={3}>
{author}
</Descriptions.Item>
<Descriptions.Item
label={'작성일'}
span={3}
style={{ textAlign: 'right' }}
>
{moment(created_date).format('YYYY.MM.DD HH:mm:ss')}
</Descriptions.Item>
<Descriptions.Item label={'게시글'} span={3}>
<br />
<div dangerouslySetInnerHTML={{ __html: content }} />
</Descriptions.Item>
</Descriptions>
</Card>
);
}