Skip to content
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: 0 additions & 1 deletion .github/workflows/pr-automation.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ jobs:
question: 'question'
};

const branchName = context.payload.pull_request.head.ref;
const parts = branchName.split('/');

if (parts.length < 3) {
Expand Down
30 changes: 26 additions & 4 deletions apps/customer/src/app/payment/success/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
"use client";

import { Suspense, useEffect, useMemo, useState } from "react";
import { Suspense, useEffect, useMemo, useRef, useState } from "react";
import { useSearchParams } from "next/navigation";
import type { StoreRandomBoxRespDTO, StoreRespDTO } from "@compasser/api";
import { useApproveKakaoPayMutation } from "@/shared/queries/mutation/payment/useApproveKakaoPayMutation";
import { useCompleteAdminSettlementMutation } from "@/shared/queries/mutation/admin-settlement/useCompleteAdminSettlementMutation";
import PurchaseCompleteModal from "@/app/(tabs)/main/store/[id]/purchase/_components/PurchaseCompleteModal";

interface PendingPayment {
Expand All @@ -15,7 +16,12 @@ interface PendingPayment {

function PaymentSuccessContent() {
const searchParams = useSearchParams();

const approveKakaoPayMutation = useApproveKakaoPayMutation();
const completeAdminSettlementMutation = useCompleteAdminSettlementMutation();

const hasRequestedRef = useRef(false);

const [pendingPayment, setPendingPayment] = useState<PendingPayment | null>(
null,
);
Expand All @@ -29,10 +35,14 @@ function PaymentSuccessContent() {
const pgToken = searchParams.get("pg_token");

useEffect(() => {
if (hasRequestedRef.current) return;

const savedPayment = sessionStorage.getItem("pendingPayment");

if (!savedPayment || !reservationId || !pgToken) return;

hasRequestedRef.current = true;

const parsedPayment = JSON.parse(savedPayment) as PendingPayment;

setPendingPayment(parsedPayment);
Expand All @@ -44,12 +54,24 @@ function PaymentSuccessContent() {
},
{
onSuccess: () => {
sessionStorage.removeItem("pendingPayment");
setIsCompleteModalOpen(true);
completeAdminSettlementMutation.mutate(
{
storeId: parsedPayment.store.storeId,
body: {
reservationIds: [reservationId],
},
},
{
onSettled: () => {
sessionStorage.removeItem("pendingPayment");
setIsCompleteModalOpen(true);
},
},
);
},
},
);
}, [reservationId, pgToken, approveKakaoPayMutation]);
}, [reservationId, pgToken]);

if (approveKakaoPayMutation.isPending) {
return <div>결제 승인 처리 중...</div>;
Expand Down
4 changes: 3 additions & 1 deletion apps/customer/src/shared/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
createMemberModule,
createOrderModule,
createPaymentModule,
createAdminSettlementModule,
} from "@compasser/api";

const tokenStore: TokenStore = {
Expand Down Expand Up @@ -44,4 +45,5 @@ export const authModule = createAuthModule(compasserApi);
export const memberModule = createMemberModule(compasserApi);
export const storeModule = createStoreModule(compasserApi);
export const orderModule = createOrderModule(compasserApi);
export const paymentModule = createPaymentModule(compasserApi);
export const paymentModule = createPaymentModule(compasserApi);
export const adminSettlementModule = createAdminSettlementModule(compasserApi);
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"use client";

import { useMutation, useQueryClient } from "@tanstack/react-query";
import { adminSettlementModule } from "@/shared/api/api";

export const useCompleteAdminSettlementMutation = () => {
const queryClient = useQueryClient();

return useMutation({
...adminSettlementModule.mutations.completeSettlement(queryClient),
});
};
127 changes: 68 additions & 59 deletions apps/owner/src/app/(tabs)/mypage/store-info/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { Button, Header } from "@compasser/design-system";
import type {
StoreUpdateReqDTO,
StoreLocationUpdateReqDTO,
StoreTag,
BankType,
} from "@compasser/api";

import StoreNameField from "@/app/signup/register/_components/fields/StoreNameField";
Expand All @@ -18,13 +20,14 @@ import PhotoUploadSection from "@/app/signup/register/_components/sections/Photo
import TagSection from "@/app/signup/register/_components/sections/TagSection";
import BusinessHoursModal from "@/app/signup/register/_components/modals/BusinessHoursModal";
import RandomBoxModal from "@/app/signup/register/_components/modals/RandomBoxModal";
import AddressSearchBottomSheet from "@/app/signup/register/_components/AddressSearchBottomSheet";
import type { AddressSearchItem } from "@/app/signup/register/_types/address-search";

import { useMyStoreQuery } from "@/shared/queries/query/useMyStoreQuery";
import { usePatchMyStoreMutation } from "@/shared/queries/mutation/auth/usePatchMyStoreMutation";
import { usePatchMyStoreLocationMutation } from "@/shared/queries/mutation/auth/usePatchMyStoreLocationMutation";
import { useRandomBoxListQuery } from "@/shared/queries/query/useRandomBoxListQuery";
import { useCreateRandomBoxMutation } from "@/shared/queries/mutation/auth/useCreateRandomBoxMutation";
import { useUpdateRandomBoxMutation } from "@/shared/queries/mutation/auth/useUpdateRandomBoxMutation";
import { useDeleteRandomBoxMutation } from "@/shared/queries/mutation/auth/useDeleteRandomBoxMutation";
import { useStoreImageQuery } from "@/shared/queries/query/useStoreImageQuery";
import { useUploadStoreImageMutation } from "@/shared/queries/mutation/auth/useUploadStoreImageMutation";
Expand All @@ -35,7 +38,21 @@ import {
EMPTY_BUSINESS_HOURS,
} from "@/app/signup/register/_utils/business-hours";

type FixedTag = "카페" | "베이커리" | "식당";
const tagOptions = ["카페", "베이커리", "식당"] as const;

type TagLabel = (typeof tagOptions)[number];

const tagMap: Record<TagLabel, StoreTag> = {
카페: "CAFE",
베이커리: "BAKERY",
식당: "RESTAURANT",
};

const reverseTagMap: Record<StoreTag, TagLabel> = {
CAFE: "카페",
BAKERY: "베이커리",
RESTAURANT: "식당",
};

export default function StoreInfoEditPage() {
const router = useRouter();
Expand All @@ -49,54 +66,39 @@ export default function StoreInfoEditPage() {
const patchMyStoreMutation = usePatchMyStoreMutation();
const patchMyStoreLocationMutation = usePatchMyStoreLocationMutation();
const createRandomBoxMutation = useCreateRandomBoxMutation();
const updateRandomBoxMutation = useUpdateRandomBoxMutation();
const deleteRandomBoxMutation = useDeleteRandomBoxMutation();
const uploadStoreImageMutation = useUploadStoreImageMutation();
const removeStoreImageMutation = useRemoveStoreImageMutation();

const [storeName, setStoreName] = useState("");
const [storeEmail, setStoreEmail] = useState("");
const [inputAddress, setInputAddress] = useState("");
const [bankName, setBankName] = useState("");
const [bankType, setBankType] = useState<BankType | "">("");
const [depositor, setDepositor] = useState("");
const [bankAccount, setBankAccount] = useState("");
const [businessHours, setBusinessHours] = useState(EMPTY_BUSINESS_HOURS);

const tagOptions: FixedTag[] = ["카페", "베이커리", "식당"];
const [selectedTag, setSelectedTag] = useState<FixedTag | "">("");

const [selectedRandomBoxIds, setSelectedRandomBoxIds] = useState<number[]>(
[],
);
const [isBusinessHoursModalOpen, setIsBusinessHoursModalOpen] =
useState(false);
const [selectedTag, setSelectedTag] = useState<"" | TagLabel>("");
const [selectedRandomBoxIds, setSelectedRandomBoxIds] = useState<number[]>([]);
const [isBusinessHoursModalOpen, setIsBusinessHoursModalOpen] = useState(false);
const [isRandomBoxModalOpen, setIsRandomBoxModalOpen] = useState(false);
const [isAddressSearchOpen, setIsAddressSearchOpen] = useState(false);

const [photoFile, setPhotoFile] = useState<File | null>(null);
const [photoPreviewUrl, setPhotoPreviewUrl] = useState("");
const [imageRemoved, setImageRemoved] = useState(false);

const mapStoreTagToLabel = (tag: string | undefined): FixedTag | "" => {
switch (tag) {
case "CAFE":
return "카페";
case "BAKERY":
return "베이커리";
case "RESTAURANT":
return "식당";
default:
return "";
}
};

useEffect(() => {
if (!myStore) return;

setStoreName(myStore.storeName ?? "");
setStoreEmail("");
setStoreEmail(myStore.storeEmail ?? "");
setInputAddress(myStore.inputAddress ?? "");
setBusinessHours(parseBusinessHours(myStore.businessHours));
setSelectedTag(mapStoreTagToLabel(myStore.tag));

if (myStore.tag) {
setSelectedTag(reverseTagMap[myStore.tag as StoreTag] ?? "");
}
}, [myStore]);

useEffect(() => {
Expand All @@ -105,6 +107,16 @@ export default function StoreInfoEditPage() {
}, [storeImage, imageRemoved]);

const businessHoursRows = useMemo(() => {
const dayKeyMap = {
mon: "MON",
tue: "TUE",
wed: "WED",
thu: "THU",
fri: "FRI",
sat: "SAT",
sun: "SUN",
} as const;

const dayLabelMap = {
mon: "월",
tue: "화",
Expand All @@ -115,19 +127,14 @@ export default function StoreInfoEditPage() {
sun: "일",
} as const;

const orderedDays = [
"mon",
"tue",
"wed",
"thu",
"fri",
"sat",
"sun",
] as const;
const orderedDays = ["mon", "tue", "wed", "thu", "fri", "sat", "sun"] as const;

return orderedDays.map((day) => {
const value = businessHours[day];
const formatted = value === "closed" ? "휴무" : value || "-";
const value = businessHours.weekly[dayKeyMap[day]];

const formatted = value.closed
? "휴무"
: `${value.open || "-"} - ${value.close || "-"}`;

return {
dayLabel: dayLabelMap[day],
Expand All @@ -136,6 +143,11 @@ export default function StoreInfoEditPage() {
});
}, [businessHours]);

const handleSelectAddress = (item: AddressSearchItem) => {
setInputAddress(item.roadAddress || item.lotNumberAddress || item.label);
setIsAddressSearchOpen(false);
};

const toggleRandomBoxSelection = (id: number) => {
setSelectedRandomBoxIds((prev) =>
prev.includes(id) ? prev.filter((item) => item !== id) : [...prev, id],
Expand All @@ -160,25 +172,13 @@ export default function StoreInfoEditPage() {
price: number;
buyLimit: number;
content: string;
boxId?: number;
pickupTimeInfo: {
start: string;
end: string;
};
}) => {
if (!storeId) return;

if (form.boxId) {
await updateRandomBoxMutation.mutateAsync({
storeId,
boxId: form.boxId,
body: {
boxName: form.boxName,
stock: form.stock,
price: form.price,
buyLimit: form.buyLimit,
content: form.content,
},
});
return;
}

await createRandomBoxMutation.mutateAsync({
storeId,
body: {
Expand All @@ -187,6 +187,7 @@ export default function StoreInfoEditPage() {
price: form.price,
buyLimit: form.buyLimit,
content: form.content,
pickupTimeInfo: form.pickupTimeInfo,
},
});
};
Expand Down Expand Up @@ -218,10 +219,11 @@ export default function StoreInfoEditPage() {
const storePayload: StoreUpdateReqDTO = {
storeName,
storeEmail,
bankName,
bankType: bankType || undefined,
depositor,
bankAccount,
businessHours,
tag: selectedTag ? tagMap[selectedTag] : undefined,
};

const locationPayload: StoreLocationUpdateReqDTO = {
Expand Down Expand Up @@ -256,17 +258,18 @@ export default function StoreInfoEditPage() {
<div className="pb-[3.6rem] pt-[1.6rem]">
<StoreNameField value={storeName} onChange={setStoreName} />
<EmailField value={storeEmail} onChange={setStoreEmail} />

<StoreAddressField
value={inputAddress}
onChange={setInputAddress}
onSearchAddress={() => {}}
onSearchAddress={() => setIsAddressSearchOpen(true)}
/>

<AccountField
bankName={bankName}
bankType={bankType}
depositor={depositor}
bankAccount={bankAccount}
onChangeBankName={setBankName}
onChangeBankType={(value) => setBankType(value as BankType)}
onChangeDepositor={setDepositor}
onChangeBankAccount={setBankAccount}
/>
Expand All @@ -293,7 +296,7 @@ export default function StoreInfoEditPage() {
/>

<TagSection
tagOptions={tagOptions}
tagOptions={[...tagOptions]}
selectedTag={selectedTag}
onSelectTag={setSelectedTag}
/>
Expand Down Expand Up @@ -326,6 +329,12 @@ export default function StoreInfoEditPage() {
onClose={() => setIsRandomBoxModalOpen(false)}
onSubmit={handleSubmitRandomBox}
/>

<AddressSearchBottomSheet
open={isAddressSearchOpen}
onClose={() => setIsAddressSearchOpen(false)}
onSelectAddress={handleSelectAddress}
/>
</>
);
}
Loading
Loading