diff --git a/.eslintrc.json b/.eslintrc.json
index 0a9380a..aae14a0 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -62,6 +62,11 @@
"group": "type",
"position": "before"
},
+ {
+ "pattern": "@/store/**/*",
+ "group": "type",
+ "position": "before"
+ },
{
"pattern": "@/styles/**/*",
"group": "type",
diff --git a/.pnp.cjs b/.pnp.cjs
index 89b910a..a20190c 100755
--- a/.pnp.cjs
+++ b/.pnp.cjs
@@ -77,7 +77,8 @@ const RAW_RUNTIME_STATE =
["typescript-plugin-css-modules", "virtual:bf4b7fdd92a9723d0b8b3c0ad1d9b3bf177b06bda2d8d90eee6bb9b559bcf7f6a4e86d3e1e4088168d00f3b758fa58c40c57bffe4a3e68627cd86f7a3c1c2191#npm:5.1.0"],\
["vite", "virtual:bf4b7fdd92a9723d0b8b3c0ad1d9b3bf177b06bda2d8d90eee6bb9b559bcf7f6a4e86d3e1e4088168d00f3b758fa58c40c57bffe4a3e68627cd86f7a3c1c2191#npm:6.0.7"],\
["vite-plugin-svgr", "virtual:bf4b7fdd92a9723d0b8b3c0ad1d9b3bf177b06bda2d8d90eee6bb9b559bcf7f6a4e86d3e1e4088168d00f3b758fa58c40c57bffe4a3e68627cd86f7a3c1c2191#npm:4.3.0"],\
- ["vite-tsconfig-paths", "virtual:bf4b7fdd92a9723d0b8b3c0ad1d9b3bf177b06bda2d8d90eee6bb9b559bcf7f6a4e86d3e1e4088168d00f3b758fa58c40c57bffe4a3e68627cd86f7a3c1c2191#npm:5.1.4"]\
+ ["vite-tsconfig-paths", "virtual:bf4b7fdd92a9723d0b8b3c0ad1d9b3bf177b06bda2d8d90eee6bb9b559bcf7f6a4e86d3e1e4088168d00f3b758fa58c40c57bffe4a3e68627cd86f7a3c1c2191#npm:5.1.4"],\
+ ["zustand", "virtual:bf4b7fdd92a9723d0b8b3c0ad1d9b3bf177b06bda2d8d90eee6bb9b559bcf7f6a4e86d3e1e4088168d00f3b758fa58c40c57bffe4a3e68627cd86f7a3c1c2191#npm:5.0.3"]\
],\
"linkType": "SOFT"\
}]\
@@ -10625,7 +10626,8 @@ const RAW_RUNTIME_STATE =
["typescript-plugin-css-modules", "virtual:bf4b7fdd92a9723d0b8b3c0ad1d9b3bf177b06bda2d8d90eee6bb9b559bcf7f6a4e86d3e1e4088168d00f3b758fa58c40c57bffe4a3e68627cd86f7a3c1c2191#npm:5.1.0"],\
["vite", "virtual:bf4b7fdd92a9723d0b8b3c0ad1d9b3bf177b06bda2d8d90eee6bb9b559bcf7f6a4e86d3e1e4088168d00f3b758fa58c40c57bffe4a3e68627cd86f7a3c1c2191#npm:6.0.7"],\
["vite-plugin-svgr", "virtual:bf4b7fdd92a9723d0b8b3c0ad1d9b3bf177b06bda2d8d90eee6bb9b559bcf7f6a4e86d3e1e4088168d00f3b758fa58c40c57bffe4a3e68627cd86f7a3c1c2191#npm:4.3.0"],\
- ["vite-tsconfig-paths", "virtual:bf4b7fdd92a9723d0b8b3c0ad1d9b3bf177b06bda2d8d90eee6bb9b559bcf7f6a4e86d3e1e4088168d00f3b758fa58c40c57bffe4a3e68627cd86f7a3c1c2191#npm:5.1.4"]\
+ ["vite-tsconfig-paths", "virtual:bf4b7fdd92a9723d0b8b3c0ad1d9b3bf177b06bda2d8d90eee6bb9b559bcf7f6a4e86d3e1e4088168d00f3b758fa58c40c57bffe4a3e68627cd86f7a3c1c2191#npm:5.1.4"],\
+ ["zustand", "virtual:bf4b7fdd92a9723d0b8b3c0ad1d9b3bf177b06bda2d8d90eee6bb9b559bcf7f6a4e86d3e1e4088168d00f3b758fa58c40c57bffe4a3e68627cd86f7a3c1c2191#npm:5.0.3"]\
],\
"linkType": "SOFT"\
}]\
@@ -14166,6 +14168,36 @@ const RAW_RUNTIME_STATE =
],\
"linkType": "HARD"\
}]\
+ ]],\
+ ["zustand", [\
+ ["npm:5.0.3", {\
+ "packageLocation": "./.yarn/cache/zustand-npm-5.0.3-6b60927ae4-dad96c6c12.zip/node_modules/zustand/",\
+ "packageDependencies": [\
+ ["zustand", "npm:5.0.3"]\
+ ],\
+ "linkType": "SOFT"\
+ }],\
+ ["virtual:bf4b7fdd92a9723d0b8b3c0ad1d9b3bf177b06bda2d8d90eee6bb9b559bcf7f6a4e86d3e1e4088168d00f3b758fa58c40c57bffe4a3e68627cd86f7a3c1c2191#npm:5.0.3", {\
+ "packageLocation": "./.yarn/__virtual__/zustand-virtual-21fdc291ee/0/cache/zustand-npm-5.0.3-6b60927ae4-dad96c6c12.zip/node_modules/zustand/",\
+ "packageDependencies": [\
+ ["zustand", "virtual:bf4b7fdd92a9723d0b8b3c0ad1d9b3bf177b06bda2d8d90eee6bb9b559bcf7f6a4e86d3e1e4088168d00f3b758fa58c40c57bffe4a3e68627cd86f7a3c1c2191#npm:5.0.3"],\
+ ["@types/immer", null],\
+ ["@types/react", "npm:18.3.18"],\
+ ["@types/use-sync-external-store", null],\
+ ["immer", null],\
+ ["react", "npm:18.3.1"],\
+ ["use-sync-external-store", null]\
+ ],\
+ "packagePeers": [\
+ "@types/immer",\
+ "@types/react",\
+ "@types/use-sync-external-store",\
+ "immer",\
+ "react",\
+ "use-sync-external-store"\
+ ],\
+ "linkType": "HARD"\
+ }]\
]]\
]\
}';
diff --git a/.yarn/cache/zustand-npm-5.0.3-6b60927ae4-dad96c6c12.zip b/.yarn/cache/zustand-npm-5.0.3-6b60927ae4-dad96c6c12.zip
new file mode 100644
index 0000000..c2ba236
Binary files /dev/null and b/.yarn/cache/zustand-npm-5.0.3-6b60927ae4-dad96c6c12.zip differ
diff --git a/package.json b/package.json
index 6fb1e0f..3ebc62c 100644
--- a/package.json
+++ b/package.json
@@ -23,7 +23,8 @@
"classnames": "^2.5.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
- "react-router-dom": "^7.1.3"
+ "react-router-dom": "^7.1.3",
+ "zustand": "^5.0.3"
},
"devDependencies": {
"@commitlint/cli": "^19.6.1",
diff --git a/src/components/ReceiptEdit/ReceiptEdit.tsx b/src/components/ReceiptEdit/ReceiptEdit.tsx
index 86c4e7d..2aaba94 100644
--- a/src/components/ReceiptEdit/ReceiptEdit.tsx
+++ b/src/components/ReceiptEdit/ReceiptEdit.tsx
@@ -8,9 +8,13 @@ import Text from "@/components/ui/Text/Text";
import { useFocus } from "@/hooks/common/useFocus";
import { useRoute } from "@/hooks/common/useRoute";
+import { useCreateReviewStore } from "@/store/useReviewStore";
+
const ReceiptEdit = () => {
const { navigateToSelectTag } = useRoute();
+ const { setOcrText } = useCreateReviewStore();
+
const [placeName, setPlaceName] = useState("청담커피 앤 토스트");
const [foodName, setFoodName] = useState("카야토스트+음료세트");
@@ -21,6 +25,13 @@ const ReceiptEdit = () => {
} = useFocus({});
const { isFocus: isFoodFocus, onFocus: handleFoodFocus, onBlur: handleFoodBlur } = useFocus({});
+ const handleInfoRightClick = () => {
+ const ocrText = `${placeName} ${foodName}`;
+ setOcrText(ocrText);
+
+ navigateToSelectTag();
+ };
+
return (
@@ -75,7 +86,7 @@ const ReceiptEdit = () => {
>
)}
diff --git a/src/components/RecognitionFail/RecognitionFail.tsx b/src/components/RecognitionFail/RecognitionFail.tsx
index 3c6ea83..8acd7e9 100644
--- a/src/components/RecognitionFail/RecognitionFail.tsx
+++ b/src/components/RecognitionFail/RecognitionFail.tsx
@@ -1,3 +1,5 @@
+import { AppBridgeMessageType } from "@/components/provider/AppBridgeProvider/AppBridgeMessage.types";
+import { useAppBridge } from "@/components/provider/AppBridgeProvider/AppBridgeProvider";
import styles from "@/components/RecognitionFail/RecognitionFail.module.scss";
import Button from "@/components/ui/Button/Button";
import Text from "@/components/ui/Text/Text";
@@ -5,7 +7,9 @@ import Text from "@/components/ui/Text/Text";
import { useRoute } from "@/hooks/common/useRoute";
const RecognitionFail = () => {
- const { navigateToHome, navigateToReceiptEdit } = useRoute();
+ const { send } = useAppBridge();
+
+ const { navigateToReceiptEdit } = useRoute();
return (
@@ -22,7 +26,11 @@ const RecognitionFail = () => {
-
+
);
diff --git a/src/components/ReviewResult/ReviewResult.tsx b/src/components/ReviewResult/ReviewResult.tsx
index a065e78..39a7fb8 100644
--- a/src/components/ReviewResult/ReviewResult.tsx
+++ b/src/components/ReviewResult/ReviewResult.tsx
@@ -3,6 +3,8 @@ import { useEffect } from "react";
import confetti from "canvas-confetti";
import HomeNavigateConfirmModal from "@/components/HomeNavigateConfirmModal/HomeNavigateConfirmModal";
+import { AppBridgeMessageType } from "@/components/provider/AppBridgeProvider/AppBridgeMessage.types";
+import { useAppBridge } from "@/components/provider/AppBridgeProvider/AppBridgeProvider";
import styles from "@/components/ReviewResult/ReviewResult.module.scss";
import Button from "@/components/ui/Button/Button";
import IconButton from "@/components/ui/IconButton/IconButton";
@@ -15,16 +17,14 @@ import useToast from "@/hooks/common/useToast";
import type { Options as ConfettiOptions } from "canvas-confetti";
const ReviewResult = () => {
+ const { send } = useAppBridge();
+
const { isOpen, handleClose, handleOpen } = useOverlay();
- const { isToast, showToast } = useToast(1000);
+ const { isToast } = useToast(1000);
const reviewText = `오늘 처음으로 청담커피 앤 토스트에서 주문했어요.. 매장도 깔끔하고 직원들도 친절해요!
음료랑 토스트 세트 시켰는데 가성비가 좋네요… 맛도 좋고 양도 많아요!! 다음에도 또 시켜먹을 거예요.`;
- const handleCopy = () => {
- showToast();
- };
-
const handleConfetti = () => {
const setting: ConfettiOptions = {
particleCount: 100,
@@ -57,7 +57,14 @@ const ReviewResult = () => {
{reviewText}
-
+
+ send({ type: AppBridgeMessageType.COPY, payload: { review: reviewText } })
+ }
+ />
diff --git a/src/components/SelectStyle/SelectStyle.tsx b/src/components/SelectStyle/SelectStyle.tsx
index c001d72..be18f3f 100644
--- a/src/components/SelectStyle/SelectStyle.tsx
+++ b/src/components/SelectStyle/SelectStyle.tsx
@@ -2,12 +2,14 @@ import { useState } from "react";
import classNames from "classnames";
+import { AppBridgeMessageType } from "@/components/provider/AppBridgeProvider/AppBridgeMessage.types";
+import { useAppBridge } from "@/components/provider/AppBridgeProvider/AppBridgeProvider";
import styles from "@/components/SelectStyle/SelectStyle.module.scss";
import Button from "@/components/ui/Button/Button";
import Icon from "@/components/ui/Icon/Icon";
import Text from "@/components/ui/Text/Text";
-import { useRoute } from "@/hooks/common/useRoute";
+import { useCreateReviewStore } from "@/store/useReviewStore";
interface StyleProps {
name: string;
@@ -22,14 +24,29 @@ const IMG_STYLE_DATA = [
];
const SelectStyle = () => {
- const { navigateToReviewResult } = useRoute();
+ const { send } = useAppBridge();
+
+ const { createReviewData, setReviewStyle } = useCreateReviewStore();
const [selectedStyle, setSelectedStyle] = useState(IMG_STYLE_DATA[0]);
+ const { ocrText, hashTag, reviewStyle } = createReviewData;
+
const handleStyleClick = (style: StyleProps) => {
setSelectedStyle((prevStyle) => (prevStyle.name === style.name ? IMG_STYLE_DATA[0] : style));
};
+ const handleCreateReview = () => {
+ if (selectedStyle.name !== "default") {
+ setReviewStyle(selectedStyle.name);
+ }
+
+ send({
+ type: AppBridgeMessageType.CREATE_REVIEW,
+ payload: { ocrText, hashTag, reviewStyle },
+ });
+ };
+
return (
@@ -63,7 +80,7 @@ const SelectStyle = () => {
-
+
);
diff --git a/src/components/SelectTag/SelectTag.tsx b/src/components/SelectTag/SelectTag.tsx
index 577f653..606cb3f 100644
--- a/src/components/SelectTag/SelectTag.tsx
+++ b/src/components/SelectTag/SelectTag.tsx
@@ -8,9 +8,13 @@ import Text from "@/components/ui/Text/Text";
import { useRoute } from "@/hooks/common/useRoute";
+import { useCreateReviewStore } from "@/store/useReviewStore";
+
const SelectTag = () => {
const { navigateToSelectStyle } = useRoute();
+ const { setHashTag } = useCreateReviewStore();
+
const [selectedTagList, setSelectedTagList] = useState([]);
const [isBottomSheetOpen, setIsBottomSheetOpen] = useState(false);
const [tagList, setTagList] = useState([
@@ -33,7 +37,7 @@ const SelectTag = () => {
setSelectedTagList((prevSelectedTags) =>
prevSelectedTags.includes(tag)
? prevSelectedTags.filter((selectedTag) => selectedTag !== tag)
- : [...prevSelectedTags, tag]
+ : [...prevSelectedTags, tag],
);
};
@@ -48,6 +52,11 @@ const SelectTag = () => {
setIsBottomSheetOpen(false);
};
+ const handleNextClick = () => {
+ setHashTag(selectedTagList);
+ navigateToSelectStyle();
+ };
+
return (
@@ -73,7 +82,7 @@ const SelectTag = () => {
-
+
{
navigateToHome: () => navigate(PATH.HOME),
navigateToBack: () => navigate(-1),
navigateToReceiptEdit: () => navigate(PATH.RECEIPT_EDIT),
- navigateToRecognitionFail: () => navigate(PATH.RECOGNITION_FAIL),
- navigateToReviewResult: () => navigate(PATH.REVIEW_RESULT),
navigateToSelectStyle: () => navigate(PATH.SELECT_STYLE),
navigateToSelectTag: () => navigate(PATH.SELECT_TAG),
};
diff --git a/src/pages/HomePage.tsx b/src/pages/HomePage.tsx
index 397e53d..564e883 100644
--- a/src/pages/HomePage.tsx
+++ b/src/pages/HomePage.tsx
@@ -1,11 +1,15 @@
import Navbar from "@/components/common/Navbar/Navbar";
import Home from "@/components/Home/Home";
+import { AppBridgeMessageType } from "@/components/provider/AppBridgeProvider/AppBridgeMessage.types";
+import { useAppBridge } from "@/components/provider/AppBridgeProvider/AppBridgeProvider";
import Icon from "@/components/ui/Icon/Icon";
import Text from "@/components/ui/Text/Text";
import { useRoute } from "@/hooks/common/useRoute";
const HomePage = () => {
+ const { send } = useAppBridge();
+
const { navigateToHome } = useRoute();
return (
@@ -14,7 +18,7 @@ const HomePage = () => {
-
+ send({ type: AppBridgeMessageType.SHARE })}>
앱 공유하기
diff --git a/src/store/useReviewStore.ts b/src/store/useReviewStore.ts
new file mode 100644
index 0000000..82197e9
--- /dev/null
+++ b/src/store/useReviewStore.ts
@@ -0,0 +1,36 @@
+import { create } from "zustand";
+
+interface CreateReviewData {
+ ocrText: string;
+ hashTag: string[];
+ reviewStyle: string;
+}
+
+interface CreateReviewDataStore {
+ createReviewData: CreateReviewData;
+ setOcrText: (ocrText: string) => void;
+ setHashTag: (hashTag: string[]) => void;
+ setReviewStyle: (reviewStyle: string) => void;
+}
+
+export const CREATE_REVIEW_DATA = {
+ ocrText: "",
+ hashTag: [],
+ reviewStyle: "",
+};
+
+export const useCreateReviewStore = create((set) => ({
+ createReviewData: { ...CREATE_REVIEW_DATA },
+ setOcrText: (ocrText: string) =>
+ set((state) => ({
+ createReviewData: { ...state.createReviewData, ocrText },
+ })),
+ setHashTag: (hashTag: string[]) =>
+ set((state) => ({
+ createReviewData: { ...state.createReviewData, hashTag },
+ })),
+ setReviewStyle: (reviewStyle: string) =>
+ set((state) => ({
+ createReviewData: { ...state.createReviewData, reviewStyle },
+ })),
+}));
diff --git a/yarn.lock b/yarn.lock
index f9727cc..cecdcbb 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -8165,6 +8165,7 @@ __metadata:
vite: "npm:^6.0.5"
vite-plugin-svgr: "npm:^4.3.0"
vite-tsconfig-paths: "npm:^5.1.4"
+ zustand: "npm:^5.0.3"
languageName: unknown
linkType: soft
@@ -11216,3 +11217,24 @@ __metadata:
checksum: 10c0/cb287fe5e6acfa82690acb43c283de34e945c571a78a939774f6eaba7c285bacdf6c90fbc16ce530060863984c906d2b4c6ceb069c94d1e0a06d5f2b458e2a92
languageName: node
linkType: hard
+
+"zustand@npm:^5.0.3":
+ version: 5.0.3
+ resolution: "zustand@npm:5.0.3"
+ peerDependencies:
+ "@types/react": ">=18.0.0"
+ immer: ">=9.0.6"
+ react: ">=18.0.0"
+ use-sync-external-store: ">=1.2.0"
+ peerDependenciesMeta:
+ "@types/react":
+ optional: true
+ immer:
+ optional: true
+ react:
+ optional: true
+ use-sync-external-store:
+ optional: true
+ checksum: 10c0/dad96c6c123fda088c583d5df6692e9245cd207583078dc15f93d255a67b0f346bad4535545c98852ecde93d254812a0c799579dfde2ab595016b99fbe20e4d5
+ languageName: node
+ linkType: hard