Skip to content

Commit

Permalink
✨ 판례/법령 저장, 불러오기 기능 구현
Browse files Browse the repository at this point in the history
  • Loading branch information
SeoYeonii committed Aug 13, 2023
1 parent b7c5536 commit f84a508
Show file tree
Hide file tree
Showing 8 changed files with 284 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/api/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ export const API_KEY = {
LAWS: "laws",
LAW_DETAIL: "lawDetail",
AI_DETAIL: "aiDetail",
STORED_LAWS: "storedLaws",
} as const;
53 changes: 53 additions & 0 deletions src/api/getStoredLaws.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
import { useQuery, UseQueryResult } from "@tanstack/react-query";

import { StoredSearchRequest } from "@/interface/profile";
import { Page } from "@/interface/search";
import { AiResponseData } from "@/interface/searchDetail";

import { API_KEY } from "./constants";

/** @TODO api 아직 안나옴! */
const getStoredLaws = async ({
type,
page,
size,
}: StoredSearchRequest): Promise<AiResponseData[]> => {
/** @TODO api 아직 안나옴! */
// }: StoredSearchRequest): Promise<Page<GetLawsResponseType<typeof type>>> => {

const response: AiResponseData[] = JSON.parse(
localStorage.getItem(`stored-${type}`) ??
JSON.stringify([] as AiResponseData[]),
);

return new Promise((res) => {
setTimeout(() => {
res(response);
}, 100);
});
// const url = `/laws/${type}?q=${q}&page=${page}&take=${size}`;
// const response: Page<GetLawsResponseType<typeof type>> | undefined =
// await http.get(url);
// const newList = response?.list.map((l) => ({ ...l, type }));
// return { ...response, list: newList } as Page<
// GetLawsResponseType<typeof type>
// >;
};

const useGetStoredLaws = ({
type,
page,
size,
}: StoredSearchRequest): UseQueryResult<
// Page<AiResponseData>
AiResponseData[]
> => {
return useQuery(
[API_KEY.STORED_LAWS, { type, page, size }],
() => getStoredLaws({ type, page, size }),
{ suspense: true },
);
};

export default useGetStoredLaws;
42 changes: 42 additions & 0 deletions src/api/putStoredLaws.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";

import { AiResponseData, StoreDetailRequest } from "@/interface/searchDetail";

import { API_KEY } from "./constants";

const putStoredLaws = async ({
type,
actionType,
content,
}: StoreDetailRequest) => {
/** @TODO api 안나옴 */
const curArr: AiResponseData[] = JSON.parse(
localStorage.getItem(`stored-${type}`) ??
JSON.stringify([] as AiResponseData[]),
);
if (content === undefined) {
// do nothing
} else if (actionType === "add") {
const newArr = [...curArr, content];
localStorage.setItem(`stored-${type}`, JSON.stringify(newArr));
} else if (actionType === "delete") {
// 일단 냅두자
}

return new Promise((res) => {
setTimeout(() => {
res({ success: true });
}, 100);
});
};

const usePutStoredLaws = () => {
const queryClient = useQueryClient();
return useMutation(putStoredLaws, {
onSuccess: () => {
queryClient.invalidateQueries([API_KEY.STORED_LAWS]);
},
});
};

export default usePutStoredLaws;
20 changes: 20 additions & 0 deletions src/assets/svg/SavedIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { ReactElement } from "react";

const SavedIcon = (): ReactElement => {
return (
<svg
xmlns="http://www.w3.org/2000/svg"
width="18"
height="20"
viewBox="0 0 18 20"
fill="#fff"
>
<path
d="M0.981323 1C0.981323 0.447715 1.42904 0 1.98132 0H16.9813C17.5336 0 17.9813 0.447715 17.9813 1V19C17.9813 19.3648 17.7826 19.7007 17.4629 19.8764C17.1431 20.0521 16.753 20.0397 16.4451 19.8441L9.48132 15.42L2.51756 19.8441C2.2096 20.0397 1.81954 20.0521 1.49978 19.8764C1.18002 19.7007 0.981323 19.3648 0.981323 19V1Z"
fill="white"
/>
</svg>
);
};

export default SavedIcon;
6 changes: 6 additions & 0 deletions src/interface/profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ export const PROFILE_TAB_INFOS: {
value: "statute",
},
];

export interface StoredSearchRequest {
type: SearchTabType;
page: number;
size: number;
}
9 changes: 9 additions & 0 deletions src/interface/searchDetail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ export const DETAIL_TAB_INFOS: {
],
};

const ACTION_TYPES = ["add", "delete"] as const;
export type ActionType = (typeof ACTION_TYPES)[number];

export interface LawDetailRequest {
type: SearchTabType;
id: string | number;
Expand All @@ -40,6 +43,12 @@ export interface AiDetailRequest {
enabled?: boolean;
}

export interface StoreDetailRequest {
type: SearchTabType;
actionType: ActionType;
content: AiResponseData | undefined;
}

export interface AiResponseData {
easyTitle?: string;
summary: string;
Expand Down
96 changes: 93 additions & 3 deletions src/pages/MyProfile/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { Avatar, Box, IconButton, Tab, Tabs, Typography } from "@mui/material";
import { useNavigate } from "react-router";
import styled from "styled-components";

import useGetStoredLaws from "@/api/getStoredLaws";
import { PROFILE_TAB_INFOS } from "@/interface/profile";
import { SearchTabType } from "@/interface/search";

Expand Down Expand Up @@ -172,12 +173,101 @@ const ContentWrapper = styled.main`
.list-area {
flex: 1;
display: flex;
width: 100%;
flex-direction: column;
padding-top: 15px;
gap: 15px;
.no-data {
background: #fdf3de;
border-radius: 33px;
display: flex;
justify-content: center;
align-items: center;
width: 100%;
height: 90%;
align-self: center;
color: var(--black-2, #3a3a3a) !important;
text-align: center !important;
font-family: SUIT !important;
font-size: 14px !important;
font-style: normal !important;
font-weight: 700 !important;
line-height: normal !important;
}
.list-item {
background: #fdf3de;
border-radius: 33px;
display: flex;
flex-direction: column;
padding: 20px;
color: var(--black-2, #3a3a3a) !important;
font-family: SUIT !important;
font-style: normal !important;
line-height: normal !important;
gap: 8px;
.title {
font-size: 15px !important;
font-weight: 700 !important;
}
.content {
font-size: 12px !important;
font-weight: 400 !important;
}
.keywords {
display: flex;
flex-wrap: wrap;
gap: 4px;
.keyword {
color: var(--deep-orange, #ff7e20);
font-family: SUIT;
font-size: 12px;
font-style: normal;
font-weight: 500;
line-height: normal;
}
}
}
}
}
`;

const LawList = (): ReactElement => {
return <div>리스트 api 대기중</div>;
const LawList = ({ type }: { type: SearchTabType }): ReactElement => {
const { data } = useGetStoredLaws({
type,
page: 1,
size: 5,
});

return (
<Box className="list-area">
{data?.length === 0 && (
<Box className="no-data">
{`${
PROFILE_TAB_INFOS.find((x) => x.value === type)?.label ??
"저장한 내용"
}${type === "prec" ? "가" : "이"} 없어요`}
</Box>
)}
{(data?.length ?? 0) > 0 &&
data?.map((d) => (
<Box className="list-item">
<Box className="title">{d.easyTitle}</Box>
<Box className="content">{d.summary}</Box>
<Box className="keywords">
{d.keywords?.map((k) => (
<Box className="keyword" key={k}>{`#${k}`}</Box>
))}
</Box>
</Box>
))}
</Box>
);
};

const MyProfile = (): ReactElement => {
Expand Down Expand Up @@ -254,7 +344,7 @@ const MyProfile = (): ReactElement => {
/>
}
>
<LawList />
<LawList type={selectedTab} />
</Suspense>
</Box>
</Box>
Expand Down
65 changes: 60 additions & 5 deletions src/pages/SearchDetail/components/AiTabPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import { Box, Button } from "@mui/material";
import styled from "styled-components";

import useGetAiDetail from "@/api/getAiDetail";
import usePutStoredLaws from "@/api/putStoredLaws";
import MoreEasyIcon from "@/assets/svg/MoreEasyIcon";
import SavedIcon from "@/assets/svg/SavedIcon";
import SaveIcon from "@/assets/svg/SaveIcon";
import { SearchTabType } from "@/interface/search";
import { DetailTabType } from "@/interface/searchDetail";
import { AiResponseData, DetailTabType } from "@/interface/searchDetail";
import Fallback from "@/pages/components/Fallback";

const StyledTabPanel = styled.div`
Expand Down Expand Up @@ -113,6 +115,17 @@ const StyledTabPanel = styled.div`
font-weight: 600;
line-height: normal;
}
.saved-button {
padding: 12px 25px;
border-radius: 14px;
background: var(--orange, #ff7e20);
color: var(--white-1, #fff);
font-family: SUIT;
font-size: 19px;
font-style: normal;
font-weight: 600;
line-height: normal;
}
}
`;

Expand Down Expand Up @@ -155,16 +168,42 @@ const AiTabPanel = ({
value: DetailTabType<typeof selectedSearchTab>;
id: string | number;
}): ReactElement => {
const [enabled, setEnabled] = useState(false);
const { data } = useGetAiDetail({
type: selectedSearchTab,
id,
});

const [enabled, setEnabled] = useState(false);
const [saved, setSaved] = useState(() => {
const curArr: AiResponseData[] = JSON.parse(
localStorage.getItem(`stored-${selectedSearchTab}`) ??
JSON.stringify([] as AiResponseData[]),
);
const target = curArr.find((x) => x.easyTitle === data?.easyTitle);
return target !== undefined;
});

const { mutate } = usePutStoredLaws();

const handleClickMoreEasy = useCallback(() => {
setEnabled(true);
}, []);

const handleClickSave = useCallback(() => {
mutate(
{
type: selectedSearchTab,
actionType: "add",
content: data,
},
{
onSuccess: () => {
setSaved(true);
},
},
);
}, []);

useEffect(() => {
const el = document.getElementById("easy-title");
if (el && el.clientHeight > 23) {
Expand Down Expand Up @@ -206,9 +245,25 @@ const AiTabPanel = ({
>
더 쉽게 해석
</Button>
<Button startIcon={<SaveIcon />} className="save-button">
판례 저장
</Button>
{!saved && (
<Button
startIcon={<SaveIcon />}
className="save-button"
onClick={handleClickSave}
>
판례 저장
</Button>
)}
{saved && (
<Button
disabled
startIcon={<SavedIcon />}
className="saved-button"
onClick={handleClickSave}
>
저장된 판례
</Button>
)}
</Box>
</StyledTabPanel>
);
Expand Down

0 comments on commit f84a508

Please sign in to comment.