Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

판례/법령 저장 불러오기 기능 구현 #12

Merged
merged 2 commits into from
Aug 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
38 changes: 19 additions & 19 deletions src/pages/Home/index.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
import {
ChangeEvent,
ReactElement,
useCallback,
useEffect,
useRef,
useState,
} from "react";
import { ChangeEvent, ReactElement, useEffect, useRef, useState } from "react";

import { observer } from "mobx-react-lite";

Expand Down Expand Up @@ -141,22 +134,27 @@ const Home = (): ReactElement => {
const { mainStore } = useStore();
const navigate = useNavigate();
const [value, setValue] = useState("");
const [isError, setIsError] = useState(false);
const [errorMsg, setErrorMsg] = useState("");

const handleTextFieldChange = useCallback(
(e: ChangeEvent<HTMLTextAreaElement>) => {
setValue(e.target.value);
},
[],
);
const handleTextFieldChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
if (isError) {
setIsError(false);
setErrorMsg("");
}
setValue(e.target.value);
};

const handleClickSearchButton = useCallback(
(v: string) => {
const handleClickSearchButton = (v: string) => {
if (value.length === 0 || value === "") {
setErrorMsg("검색어는 빈칸 일 수 없어요.");
setIsError(true);
} else {
mainStore.resetSearchWords();
mainStore.addSearchWord(v);
navigate("/search");
},
[navigate],
);
}
};

useEffect(() => {
const wheelHandler = (e: WheelEvent) => {
Expand Down Expand Up @@ -231,6 +229,8 @@ const Home = (): ReactElement => {
<Box className="bottom-area">
<Box className="search-area">
<SearchBarWithButton
isError={isError}
errorMsg={errorMsg}
value={value}
onChange={handleTextFieldChange}
placeholder="키워드 또는 사건번호 입력"
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
Loading