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
6 changes: 4 additions & 2 deletions app/routes/business/proposal/sent-campaign-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ import { useSearchParams, useNavigate } from "react-router-dom";
import { getProposalDetail, type ProposalDetail } from "./api/proposal";
import { axiosInstance } from "../../../api/axios";
import { getBrandSummary, type BrandSummary } from "./api/brand";
import Header from "../../../components/layout/Header";
import CampaignBrandCard from "../components/CampaignBrandCard";
import LoadingSpinner from "../../../components/common/LoadingSpinner";
import CampaignInfoGroup from "../components/CampaignInfoGroup";
import { useHideHeader } from "../../../hooks/useHideHeader";
import NavigationHeader from "../../../components/common/NavigateHeader";

import dropdownIcon from "../../../assets/arrow-down.svg";
import dropupIcon from "../../../assets/arrow-up.svg";
Expand All @@ -23,6 +24,7 @@ export default function SentCampaignContent() {
const [brandUserId, setBrandUserId] = useState<string | null>(null);
const [brandCategory, setBrandCategory] = useState<string | null>(null);
const [isLoading, setIsLoading] = useState(true);
useHideHeader(true);

const proposalId = searchParams.get("proposalId");

Expand Down Expand Up @@ -63,7 +65,7 @@ export default function SentCampaignContent() {

return (
<div className="flex flex-col w-full min-h-screen bg-bg-w font-pretendard">
<Header title="캠페인 보기" />
<NavigationHeader title="캠페인 보기" onBack={() => navigate(-1)} />

<main className="flex flex-col pb-24">
{/* 상단 브랜드 정보 및 채팅 섹션 */}
Expand Down
7 changes: 3 additions & 4 deletions app/routes/business/proposal/sent-proposal-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { getProposalDetail, type ProposalDetail } from "./api/proposal";
import { getBrandSummary, type BrandSummary } from "./api/brand";
import { getProfileCard, type ProfileCard } from "./api/user";
import { cancelCampaignProposal } from "./api/proposal";

import { useHideHeader } from "../../../hooks/useHideHeader";

import NavigationHeader from "../../../components/common/NavigateHeader";
import CampaignBrandCard from "../components/CampaignBrandCard";
import LoadingSpinner from "../../../components/common/LoadingSpinner";
Expand All @@ -23,6 +23,7 @@ export default function ProposalContent() {
const [isContentOpen, setIsContentOpen] = useState(false);
const [isConfirmOpen, setIsConfirmOpen] = useState(false);
const navigate = useNavigate();
useHideHeader(true);

const [data, setData] = useState<ProposalDetail | null>(null);
const [brand, setBrand] = useState<BrandSummary | null>(null);
Expand Down Expand Up @@ -94,9 +95,7 @@ export default function ProposalContent() {

return (
<div className="flex flex-col w-full min-h-screen bg-bg-w font-pretendard">
<div className="min-h-[60px]">
<NavigationHeader title="제안 보기" onBack={() => navigate(-1)} />
</div>
<NavigationHeader title="제안 보기" onBack={() => navigate(-1)} />

<main className="flex flex-col pb-24">
{/* 브랜드 카드 및 제안 프로필 */}
Expand Down
4 changes: 2 additions & 2 deletions app/routes/chat/resuggest/resuggest-content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ export default function ReSuggestContent() {
{/* 커스텀 브랜드 카드 디자인 */}
<div className="flex gap-4 w-full py-4 mb-2">
{/* 로고 영역 */}
<div className="w-[84px] h-[84px] rounded-[12px] border border-bluegray-2 overflow-hidden bg-white flex items-center justify-center p-2.5">
<div className="w-[64px] h-[64px] rounded-[5px] border border-[#E6E6F3] overflow-hidden bg-white flex items-center justify-center p-2.5">
<img
src={brandDetail?.logoImageUrl || ""}
className="w-full h-full object-contain"
Expand All @@ -212,7 +212,7 @@ export default function ReSuggestContent() {
{/* 첫 번째 줄: 브랜드명 및 매칭률 */}
<div className="flex justify-between items-start w-full">
<div className="flex items-center gap-1.5 pt-0.5">
<span className="text-title7 text-text-black">
<span className="text-title1 text-text-black">
{brandDetail?.name || proposalData?.brandName || ""}
</span>
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#667085" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
Expand Down
18 changes: 4 additions & 14 deletions app/routes/matching/components/ProfileSelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,10 @@ export default function ProfileSelector({
className="flex items-center justify-between w-full py-[14px] px-4 gap-2.5 rounded-xl border border-core-70 bg-bluegray-2"
>
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-full bg-text-gray5 flex items-center justify-center">
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M12 12C14.21 12 16 10.21 16 8C16 5.79 14.21 4 12 4C9.79 4 8 5.79 8 8C8 10.21 9.79 12 12 12ZM12 14C9.33 14 4 15.34 4 18V20H20V18C20 15.34 14.67 14 12 14Z"
fill="#9B9BA1"
/>
</svg>
</div>
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M16 9C16 10.0609 15.5786 11.0783 14.8284 11.8284C14.0783 12.5786 13.0609 13 12 13C10.9391 13 9.92172 12.5786 9.17157 11.8284C8.42143 11.0783 8 10.0609 8 9C8 7.93913 8.42143 6.92172 9.17157 6.17157C9.92172 5.42143 10.9391 5 12 5C13.0609 5 14.0783 5.42143 14.8284 6.17157C15.5786 6.92172 16 7.93913 16 9ZM14 9C14 9.53043 13.7893 10.0391 13.4142 10.4142C13.0391 10.7893 12.5304 11 12 11C11.4696 11 10.9609 10.7893 10.5858 10.4142C10.2107 10.0391 10 9.53043 10 9C10 8.46957 10.2107 7.96086 10.5858 7.58579C10.9609 7.21071 11.4696 7 12 7C12.5304 7 13.0391 7.21071 13.4142 7.58579C13.7893 7.96086 14 8.46957 14 9Z" fill="#6666E5"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12 1C5.925 1 1 5.925 1 12C1 18.075 5.925 23 12 23C18.075 23 23 18.075 23 12C23 5.925 18.075 1 12 1ZM3 12C3 14.09 3.713 16.014 4.908 17.542C5.74744 16.4401 6.83015 15.5471 8.07164 14.9327C9.31312 14.3183 10.6798 13.9991 12.065 14C13.4324 13.9984 14.7821 14.3091 16.0111 14.9084C17.2402 15.5077 18.3162 16.3797 19.157 17.458C20.0234 16.3216 20.6068 14.9952 20.8589 13.5886C21.111 12.182 21.0244 10.7355 20.6065 9.36898C20.1886 8.00243 19.4512 6.75505 18.4555 5.73004C17.4598 4.70503 16.2343 3.93186 14.8804 3.47451C13.5265 3.01716 12.0832 2.88877 10.6699 3.09997C9.25652 3.31117 7.91379 3.85589 6.75277 4.68905C5.59175 5.52222 4.64581 6.61987 3.99323 7.8912C3.34065 9.16252 3.00018 10.571 3 12ZM12 21C9.93391 21.0033 7.93014 20.2926 6.328 18.988C6.97281 18.0646 7.83119 17.3107 8.83008 16.7905C9.82896 16.2702 10.9388 15.999 12.065 16C13.1772 15.999 14.2735 16.2635 15.263 16.7713C16.2524 17.2792 17.1064 18.0158 17.754 18.92C16.1395 20.267 14.1026 21.0033 12 21Z" fill="#6666E5"/>
</svg>
<span className="text-title3 text-text-black">{username}</span>
</div>
<svg
Expand Down
72 changes: 66 additions & 6 deletions app/routes/room/components/Bubbles/ProposalMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,14 @@ export default function ProposalMessage(props: Props) {
const [isProcessing, setIsProcessing] = useState(false);
const [actionDone, setActionDone] = useState<"accepted" | "rejected" | null>(null);
const [modalState, setModalState] = useState<"confirm" | "success" | null>(null);
const [acceptFlowStarted, setAcceptFlowStarted] = useState(false);

const isAlreadyProcessed = proposalStatus === "MATCHED" || proposalStatus === "REJECTED" || proposalStatus === "CANCELED";
const showButtons = proposalDirection === "BRAND_TO_CREATOR" && !isAlreadyProcessed && !actionDone;

const handleAcceptClick = () => {
if (isProcessing) return;
setAcceptFlowStarted(true);
setModalState("confirm");
};

Expand All @@ -65,38 +67,50 @@ export default function ProposalMessage(props: Props) {
setActionDone("accepted");
} else {
setModalState(null);
setAcceptFlowStarted(false);
alert(response.message || "수락 처리 중 오류가 발생했습니다.");
}
} catch (error) {
console.error("제안 수락 실패:", error);
setModalState(null);
setAcceptFlowStarted(false);
alert("서버와 통신 중 에러가 발생했습니다.");
} finally {
setIsProcessing(false);
}
};

const handleReject = () => {
if (isProcessing) return;
if (acceptFlowStarted) return;
if (actionDone === "accepted") return;

navigate(`/business/proposal?type=received&proposalId=${proposalId}`, {
state: { openReject: true },
});
};

const closeAcceptModal = () => {
if (isProcessing) return;
setModalState(null);
setAcceptFlowStarted(false);
};

const AcceptModal = () => {
if (!modalState) return null;

return (
<div className="fixed inset-0 z-50 flex items-center justify-center">
<div
className="absolute inset-0 bg-black/40"
onClick={() => !isProcessing && setModalState(null)}
onClick={() => !isProcessing && closeAcceptModal()}
/>

<div className="relative bg-white rounded-[20px] w-[calc(100%-48px)] max-w-[400px] px-6 pt-6 pb-8 flex flex-col items-center">
{modalState === "confirm" && (
<button
type="button"
onClick={() => setModalState(null)}
onClick={() => closeAcceptModal()}
className="absolute top-5 left-5 w-8 h-8 flex items-center justify-center"
>
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
Expand All @@ -118,7 +132,7 @@ export default function ProposalMessage(props: Props) {
<div className="w-full flex items-center gap-3">
<button
type="button"
onClick={() => setModalState(null)}
onClick={() => closeAcceptModal()}
className="w-[120px] h-[54px] rounded-[14px] border border-[#B7B7F3] text-[#6666E5] text-[17px] font-semibold shrink-0"
>
취소
Expand All @@ -144,7 +158,7 @@ export default function ProposalMessage(props: Props) {

<button
type="button"
onClick={() => setModalState(null)}
onClick={closeAcceptModal}
className="w-full h-[54px] rounded-[14px] bg-[#6666E5] text-white text-[17px] font-semibold"
>
완료하기
Expand All @@ -169,6 +183,52 @@ export default function ProposalMessage(props: Props) {
</button>
);

if (kind === "APPLY_CARD") {
return (
<div className="flex w-full justify-end">
<div className="inline-flex items-end gap-[8px]">
{timeText ? (
<div className="text-[10px] leading-[12px] text-[#9B9BA1] text-right whitespace-pre-line">
{timeText}
</div>
) : null}

<div className="w-[214px] rounded-[10px] bg-[#B7B7F380] px-[10px] py-[10px] text-left break-words whitespace-pre-line gap-[10px] flex flex-col">
<div className="gap-[2px]">
<div className="text-[10px] leading-[14px] style-Medium text-[#6666E5]">
지원
</div>

<div className="gap-[5px]">
<div className="text-[12px] leading-[16px] style-Medium text-black">
캠페인 명
</div>

<div className="flex items-center">
<div className="min-w-0 text-[14px] leading-[20px] style-Medium text-[#404252] truncate">
{campaignName}
</div>
<ArrowButton onClick={() => navigate(`/business/proposal?type=sent&proposalId=${proposalId}`)} />
</div>
</div>
</div>

<div>
<div className="text-[12px] leading-[16px] style-Medium text-black">
지원 내용
</div>

<div className="mt-[2px] text-[10px] leading-[14px] text-[#404252] truncate">
{bodyText}
</div>
</div>
</div>
</div>
</div>
);
}


if (proposalDirection == "CREATOR_TO_BRAND") {
return (
<div className="flex w-full justify-end">
Expand All @@ -179,7 +239,7 @@ export default function ProposalMessage(props: Props) {
</div>
) : null}

<div className="max-w-[214px] w-full rounded-[10px] bg-[#B7B7F380] px-[10px] py-[10px] text-left break-words whitespace-pre-line gap-[10px] flex flex-col">
<div className="w-[214px] rounded-[10px] bg-[#B7B7F380] px-[10px] py-[10px] text-left break-words whitespace-pre-line gap-[10px] flex flex-col">
<div className="gap-[2px]">
<div className="text-[10px] leading-[14px] style-Medium text-[#6666E5]">
{kind === "RE_PROPOSAL_CARD" ? "재제안" : "제안"}
Expand Down Expand Up @@ -288,7 +348,7 @@ export default function ProposalMessage(props: Props) {
<button
type="button"
onClick={handleReject}
disabled={isProcessing}
disabled={isProcessing || acceptFlowStarted || actionDone === "accepted"}
className="w-[72px] h-[32px] rounded-[6px] bg-white text-[#6666E5] text-[14px] leading-[20px] style-Medium border border-[#B7B7F3] disabled:opacity-50"
>
거절하기
Expand Down