diff --git a/src/components/screens/ChallengeScreen.jsx b/src/components/screens/ChallengeScreen.jsx index 2ae1ceb..b60a78a 100644 --- a/src/components/screens/ChallengeScreen.jsx +++ b/src/components/screens/ChallengeScreen.jsx @@ -273,7 +273,7 @@ function ChallengeCard({ }) { const [showModal, setShowModal] = useState(false); const [selectedType, setSelectedType] = useState(null); - // ✅ 남은시간 계산 및 실시간 갱신 (진행중 + 참여가능) + // 남은시간 계산 및 실시간 갱신 (진행중 + 참여가능) const [remainingTime, setRemainingTime] = useState(''); const [isExpired, setIsExpired] = useState(false); @@ -312,7 +312,7 @@ function ChallengeCard({ const minutes = Math.floor((diff / (1000 * 60)) % 60); const seconds = Math.floor((diff / 1000) % 60); - // ✅ 형식: “3일 4시간 22분 18초” + // 형식: “3일 4시간 22분 18초” setRemainingTime(`${days}일 ${hours}시간 ${minutes}분 ${seconds}초`); setIsExpired(false); }; diff --git a/src/components/screens/PointExchangeScreen.jsx b/src/components/screens/PointExchangeScreen.jsx index 4a2c2cf..4cab4a8 100644 --- a/src/components/screens/PointExchangeScreen.jsx +++ b/src/components/screens/PointExchangeScreen.jsx @@ -30,6 +30,10 @@ import { convertVoucherToGifticon, formatDate } from '../../util/pointApi'; export default function PointExchangeScreen({ onNavigate }) { const dispatch = useDispatch(); + const [showPhoneModal, setShowPhoneModal] = useState(false); + const [phoneNumber, setPhoneNumber] = useState(''); + const [phoneError, setPhoneError] = useState(false); + // Redux로 포인트샵 데이터 가져오기 const { data: shopData, loading: isLoading, error } = usePointShop(); const { spendPoint, loading: isSpending } = useSpendPoint(); @@ -55,6 +59,34 @@ export default function PointExchangeScreen({ onNavigate }) { const [showTransferModal, setShowTransferModal] = useState(false); const [savedAccounts, setSavedAccounts] = useState([]); + const handleGifticonConfirm = () => { + // 구매 확인 모달 닫고 → 전화번호 입력 모달로 이동 + setShowConfirmModal(false); + setShowPhoneModal(true); + }; + + const handlePhoneSubmit = async () => { + if (!phoneNumber.trim()) { + setPhoneError(true); + return; + } + setPhoneError(false); + setShowPhoneModal(false); + + try { + await spendPoint({ + point: selectedGifticon.voucherId, // voucher_id 전달 + type: 'VOUCHER', + }); + setShowSuccessModal(true); + dispatch(fetchPointShop()); + dispatch(fetchUsedPointLogs()); + } catch (error) { + console.error('포인트 사용 실패:', error); + alert('구매에 실패했습니다: ' + (error.message || '알 수 없는 오류')); + } + }; + // 컴포넌트 마운트 시 포인트샵 데이터 가져오기 useEffect(() => { dispatch(fetchPointShop()); @@ -172,7 +204,7 @@ export default function PointExchangeScreen({ onNavigate }) { console.error('포인트전환 실패:', error); alert( '포인트전환 신청에 실패했습니다: ' + - (error.message || '알 수 없는 오류') + (error.message || '알 수 없는 오류') ); } }; @@ -230,22 +262,20 @@ export default function PointExchangeScreen({ onNavigate }) {
@@ -407,11 +435,10 @@ export default function PointExchangeScreen({ onNavigate }) { ) } disabled={!canAfford} - className={`w-full py-2.5 px-3 rounded-lg text-sm font-bold transition-all ${ - canAfford + className={`w-full py-2.5 px-3 rounded-lg text-sm font-bold transition-all ${canAfford ? 'bg-[#4CAF50] text-white hover:bg-[#45a049] shadow-sm' : 'bg-gray-100 text-gray-400 cursor-not-allowed' - }`} + }`} > {canAfford ? '구매하기' @@ -655,7 +682,7 @@ export default function PointExchangeScreen({ onNavigate }) {

) : usedLogs && - usedLogs.filter((item) => item.pointAmount < 0).length > 0 ? ( + usedLogs.filter((item) => item.pointAmount < 0).length > 0 ? (
{usedLogs .filter((item) => item.pointAmount < 0) // 사용(음수)만 필터링 @@ -679,13 +706,12 @@ export default function PointExchangeScreen({ onNavigate }) {
{isVoucher ? ( @@ -795,17 +821,93 @@ export default function PointExchangeScreen({ onNavigate }) { 취소 + +
+ + + )} + + + {/* 전화번호 입력 모달 */} + + {showPhoneModal && ( + setShowPhoneModal(false)} + > + e.stopPropagation()} + className="bg-white rounded-3xl p-6 max-w-sm w-full text-center" + > + + + + +

수령자 정보 입력

+

+ 기프티콘을 받을 휴대폰 번호를 입력해주세요 📱 +

+ + setPhoneNumber(e.target.value)} + placeholder="010-1234-5678" + className={`w-full border rounded-xl px-3 py-2 text-center text-gray-700 focus:outline-none focus:ring-2 ${phoneError + ? 'border-red-400 focus:ring-red-300' + : 'border-gray-300 focus:ring-[#4CAF50]' + }`} + /> + {phoneError && ( +

+ 번호를 입력해주세요. +

+ )} + +

+ ※ 입력된 번호는 저장되지 않습니다. +

+ +
+ +
)}
+ {/* 포인트전환 확인 모달 */} {showTransferModal && ( @@ -824,8 +926,8 @@ export default function PointExchangeScreen({ onNavigate }) { className='bg-white rounded-3xl p-6 max-w-sm w-full' >
-
- +
+

포인트전환 신청 확인 @@ -865,7 +967,7 @@ export default function PointExchangeScreen({ onNavigate }) { {Math.ceil( parseInt(transferAmount || 0) * - 1.05 + 1.05 ).toLocaleString()} P @@ -874,7 +976,7 @@ export default function PointExchangeScreen({ onNavigate }) { 입금 예정액 - + {parseInt( transferAmount || 0 ).toLocaleString()} @@ -895,7 +997,7 @@ export default function PointExchangeScreen({ onNavigate }) { @@ -912,7 +1014,7 @@ export default function PointExchangeScreen({ onNavigate }) { initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} - className='fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4' + className="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4" onClick={() => setShowSuccessModal(false)} > e.stopPropagation()} - className='bg-white rounded-3xl p-6 max-w-sm w-full text-center' + className="bg-white rounded-3xl p-6 max-w-sm w-full text-center" > - + -

- 신청 완료! -

-

+ +

신청 완료!

+ + {/* {activeTab === 'gifticon' && ( +
+

+ 기프티콘을 받을 번호를 입력해주세요 📱 +

+ console.log('입력값:', e.target.value)} + /> +

+ ※ 입력한 번호는 저장되지 않습니다. +

+
+ )} */} + + +

{activeTab === 'gifticon' - ? '구매가 완료되었습니다. 등록하신 번호로 기프티콘이 발송되었습니다.' - : '포인트전환 신청이 완료되었습니다. 영업일 기준 1-3일 내 입금됩니다.'} + ? '번호 입력 후 해당 번호로 기프티콘이 발송됩니다. ( 영업일 기준 1~3일 내 )' + : '포인트전환 신청이 완료되었습니다. 영업일 기준 1~3일 내 입금됩니다.'}

+ @@ -952,6 +1074,7 @@ export default function PointExchangeScreen({ onNavigate }) {
)} +

); }