Skip to content

Commit

Permalink
chore : 키워드 편지 상세페이지 수정 (#292)
Browse files Browse the repository at this point in the history
* feat :  올바른 페이지로 가도록 naviagate

* chore : 편지 상세 보기 수정

* chore : router 수정

* chroe : api 에러처리 수정

* chore : 페이지 수정

* chore : 스토리지 페이지 스타일 변경

* style : style 수정
  • Loading branch information
HelloWook authored Dec 7, 2024
1 parent f5945c7 commit c83b7e0
Show file tree
Hide file tree
Showing 9 changed files with 210 additions and 172 deletions.
18 changes: 13 additions & 5 deletions src/components/Common/TextArea/TextArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,17 @@ import { clsx } from 'clsx';

type TextAreaProps = {
value: string;
setValue: (value: string) => void;
setValue?: (value: string) => void;
font?: string;
isReadonly?: boolean;
};

export const TextArea = ({ value, setValue, font }: TextAreaProps) => {
export const TextArea = ({
value,
setValue,
font,
isReadonly
}: TextAreaProps) => {
const [lineHeight, setLineHeight] = useState<number>(2.2);
const [lineCount, setLineCount] = useState<number>(8);
const textAreaRef = useRef<HTMLTextAreaElement>(null);
Expand All @@ -35,8 +41,9 @@ export const TextArea = ({ value, setValue, font }: TextAreaProps) => {

setLineCount(calculatedLinesCount);
}

setValue(inputValue);
if (setValue) {
setValue(inputValue);
}
};

useEffect(() => {
Expand Down Expand Up @@ -82,7 +89,7 @@ export const TextArea = ({ value, setValue, font }: TextAreaProps) => {
<div>
<textarea
className={clsx(
`w-full m-auto overflow-hidden bg-transparent border-none resize-none min-h-[413px] min-w-[281px]`,
`w-full m-auto overflow-hidden bg-transparent border-none resize-none min-h-[413px] min-w-[281px] focus:outline-none`,
font ? font : 'font-sans'
)}
style={{
Expand All @@ -92,6 +99,7 @@ export const TextArea = ({ value, setValue, font }: TextAreaProps) => {
placeholder="편지를 작성하세요..."
value={value}
onChange={handleInputChange}
readOnly={isReadonly}
/>

<div className="absolute top-0 w-full mt-[30px]">
Expand Down
42 changes: 42 additions & 0 deletions src/components/LetterDetailPage/Keyword/KeywordList.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { Margin } from '@/components/Common/Margin/Margin';
import React, { useState } from 'react';
import { IoIosArrowDown, IoIosArrowUp } from 'react-icons/io';
type KeywordListProps = {
keywords: string[];
};

export const KeywordList = ({ keywords }: KeywordListProps) => {
const [isOpen, setIsOpen] = useState(false);

const onClick = () => {
setIsOpen((prev) => !prev);
};
return (
<>
{keywords.length > 0 && (
<p
className={`flex flex-wrap ${isOpen ? '' : 'max-w-[550px] overflow-hidden'}`}
>
{keywords
.slice(0, isOpen ? keywords.length : 4)
.map((keyword, index) => (
<span key={index} className="keyword-tag key">
{keyword}
</span>
))}
{!isOpen && keywords.length > 4 && (
<button className="flex items-center" onClick={onClick}>
<span className="text-4xl">...</span>
<IoIosArrowDown className="text-3xl " />
</button>
)}
{isOpen && keywords.length > 4 && (
<button className="flex items-center" onClick={onClick}>
<IoIosArrowUp className="text-3xl " />
</button>
)}
</p>
)}
</>
);
};
Original file line number Diff line number Diff line change
@@ -1,72 +1,47 @@
import { useState } from 'react';
import { IoIosArrowDown, IoIosArrowUp } from 'react-icons/io';
import { formatDate } from '@/util/formatDate';
import { TextArea } from '@/components/Common/TextArea/TextArea';
import { Margin } from '@/components/Common/Margin/Margin';
import { KeywordList } from '../Keyword/KeywordList';
import { DeleteButton } from '../Delete/DeleteButton';
import clsx from 'clsx';

type KeywordLetterDetailProps = {
letterData: {
letterId: number;
title: string;
content: string;
keywords: string[];
createdAt: string;
font: string;
};
};

export const KeywordLetterDetail = ({
letterData
}: KeywordLetterDetailProps) => {
const [isOpen, setIsOpen] = useState(false);

const onClick = () => {
setIsOpen((prev) => !prev);
};
const { title, content, keywords, createdAt } = letterData;
const { letterId, title, content, keywords, createdAt, font } = letterData;
return (
<>
<p className="absolute left-24 top-[15rem]">{title}</p>
<p className="absolute left-24 top-[19rem]">{content}</p>
<div className="absolute bottom-16 w-[580px] h-[100px]">
{keywords.length > 0 && (
<>
<p className="font-bold m-4">편지의 키워드</p>
<div className="m-4">
<p
className={`flex flex-wrap ${isOpen ? '' : 'max-w-[550px] overflow-hidden'}`}
>
{keywords
.slice(0, isOpen ? keywords.length : 4)
.map((keyword, index) => (
<span
key={index}
className="mr-2 mb-2 keyword-tag"
>
{keyword}
</span>
))}
{!isOpen && keywords.length > 4 && (
<button
className="flex items-center"
onClick={onClick}
>
<span className="text-4xl">...</span>
<IoIosArrowDown className="text-3xl mr-2" />
</button>
)}
{isOpen && keywords.length > 4 && (
<button
className="flex items-center"
onClick={onClick}
>
<IoIosArrowUp className="text-3xl mr-2" />
</button>
)}
</p>
</div>
</>
)}
</div>
<div className="absolute bottom-8 translate-x-60 flex-col">
<p className="ml-2">{formatDate(createdAt)}</p>
<div className={clsx(font ? font : 'font-sans')}>
<Margin top={20} />
<div className="relative z-20 flex flex-col justify-center w-9/12 m-auto py-9">
<div className="absolute top-0 right-0">
<DeleteButton id={String(letterId)} />
</div>
<h1>{title}</h1>
<img src={'/to_line.f4c129e6.svg'} className="w-full" />

<div className="relative">
<TextArea value={content} font={font} isReadonly={true} />
</div>

<Margin top={30} />
<div className="flex justify-between w-full ">
<p className="font-bold ">편지의 키워드</p>
<p className="">{formatDate(createdAt)}</p>
</div>
<KeywordList keywords={keywords} />
<Margin bottom={30} />
</div>
</>
</div>
);
};
Original file line number Diff line number Diff line change
@@ -1,14 +1,9 @@
import { BackButton } from '@/components/Common/BackButton/BackButton';
import { useNavigate } from 'react-router-dom';

import { useParams } from 'react-router-dom';
import { DeleteButton } from '@/components/LetterDetailPage/Delete/DeleteButton';

import { ReportButton } from '@/components/LetterDetailPage/Report/ReportButton';
import { useKeywordLetterDetail } from '@/hooks/useGetKeywordLetterDetail';
import { MapLetterDetail } from '../LetterDatail/MapLetterDetail';
import { ThemeWrapper } from '@/components/CreatLetterPage/ThemeWrapper/ThemeWrapper';
import { useToastStore } from '@/hooks';
import { useEffect } from 'react';
import { KeywordLetterDetail } from '../LetterDatail/KeywordLetterDetail';
import { ReplyList } from '../ReplyList/ReplyList';

type LetterDetailContainerProps = {
hasReplies?: boolean;
Expand All @@ -21,106 +16,92 @@ export const LetterDetailContainer = ({
type: 'map' | 'keyword';
letterId: string;
}>();
const { data, isLoading, error } = useKeywordLetterDetail({

const { addToast } = useToastStore();

const { data, error, isLoading } = useKeywordLetterDetail({
letterId: letterId || ''
});

const navigate = useNavigate();

const onBackClick = () => {
navigate(-1);
};
useEffect(() => {
if (error) {
addToast(error.message, 'error');
}
}, [error, addToast]);

if (isLoading) {
return <div>Loading...</div>;
return <div>로딩 중...</div>;
}

if (error instanceof Error) {
console.error('error:', error.message);
return <div>Error: {error.message}</div>;
if (!data) {
return (
<ThemeWrapper themeId={1}>
<div>데이터가 없습니다.</div>;
</ThemeWrapper>
);
}

const imageItem = {
id: '편지지_샘플_1',
name: '이미지',
src: '/편지지_샘플_1.png'
};
const labelItem = {
id: '라벨_샘플',
name: '이미지',
src: '/라벨_샘플.png'
};

const sampleReplies = [
{ id: 1, title: '답장 제목 1', date: '24.11.28' },
{ id: 2, title: '답장 제목 2', date: '24.11.29' },
{ id: 3, title: '답장 제목 3', date: '24.11.30' }
];
return (
<>
<div className="relative mx-auto mt-4 max-w">
<div className="mx-auto w-[710px]">
<BackButton onClick={onBackClick} />
</div>
{letterId && (
<div className="absolute top-0 flex mt-10 right-8">
<DeleteButton id={letterId} />
{!data?.isOwner && <ReportButton id={letterId} />}
</div>
)}
<div className="relative mt-16 flex-center">
<img
src={imageItem.src}
alt={imageItem.name}
className="w-[710px] h-[900px] relative"
/>
<img
src={labelItem.src}
alt={labelItem.name}
className="absolute top-4 translate-x-40 w-[125.32px] h-[201.1px]"
/>
{type === 'map' ? (
<MapLetterDetail
title="편지제목"
content="편지내용"
date="24.11.18"
place="서울시 종로구 평창동"
hint="서대문역 앞 붕어빵 가게에서"
/>
) : (
data && <KeywordLetterDetail letterData={data} />
<ThemeWrapper themeId={Number(data.paper)}>
<KeywordLetterDetail letterData={data} />
</ThemeWrapper>
);
};

/*
<div className="relative mx-auto mt-4 max-w">
{letterId && (
<div className="absolute top-0 flex mt-10 right-8">
<DeleteButton id={letterId} />
{!data?.isOwner && <ReportButton id={letterId} />}
</div>
)}
<div className="relative mt-16 flex-center">
<img
src={labelItem.src}
alt={labelItem.name}
className="absolute top-4 translate-x-40 w-[125.32px] h-[201.1px]"
/>
{type === 'map' ? (
<MapLetterDetail
title="편지제목"
content="편지내용"
date="24.11.18"
place="서울시 종로구 평창동"
hint="서대문역 앞 붕어빵 가게에서"
/>
) : (
data && <KeywordLetterDetail letterData={data} />
)}
</div>
</div>
</div>
{data?.isOwner ? (
hasReplies ? (
<div className="mt-16 w-[710px] mx-auto">
<ReplyList replies={sampleReplies} />
{data?.isOwner ? (
hasReplies ? (
<div className="mt-16 w-[710px] mx-auto">
<ReplyList replies={sampleReplies} />
</div>
) : null
) : type === 'map' ? (
<div className="gap-4 mx-auto mt-4 flex-center max-w">
{!data?.isOwner && (
<>
<button className="btn-base rounded-3xl w-[339.82px] h-[80px]">
보관하기
</button>
<button className="btn-base rounded-3xl w-[339.82px] h-[80px]">
편지에 답장하기
</button>
</>
)}
</div>
) : null
) : type === 'map' ? (
<div className="gap-4 mx-auto mt-4 flex-center max-w">
{!data?.isOwner && (
<>
<button className="btn-base rounded-3xl w-[339.82px] h-[80px]">
보관하기
</button>
<button className="btn-base rounded-3xl w-[339.82px] h-[80px]">
) : (
<div className="gap-4 mx-auto mt-4 flex-center max-w">
{!data?.isOwner && (
<button className="btn-base rounded-3xl w-[700px] h-[80px]">
편지에 답장하기
</button>
</>
)}
</div>
) : (
<div className="gap-4 mx-auto mt-4 flex-center max-w">
{!data?.isOwner && (
<button className="btn-base rounded-3xl w-[700px] h-[80px]">
편지에 답장하기
</button>
)}
</div>
)}
</>
);
};
)}
</div>
)}
*/
Loading

0 comments on commit c83b7e0

Please sign in to comment.