Skip to content

Commit

Permalink
feat: 배너메세지 경로별 수정
Browse files Browse the repository at this point in the history
feat: 배너메세지 경로별 수정
  • Loading branch information
Cllaude99 authored Aug 18, 2024
2 parents 63acb24 + a0212b7 commit 7a2204e
Show file tree
Hide file tree
Showing 4 changed files with 150 additions and 107 deletions.
2 changes: 1 addition & 1 deletion src/apis/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ export const REFRESH_URL = BACKEND_URL + '/api/auth/refresh';

// login이 완료된 사람의 요청의 경우 axiosInstance를 사용하여 요청
export const axiosInstance = axios.create({
baseURL: 'https://www.api.cotato-midpoint.site',
baseURL: BACKEND_URL,
});

// accessToken, refreshToken 재발급하는 함수
Expand Down
119 changes: 76 additions & 43 deletions src/components/common/shared/BannerMessage.tsx
Original file line number Diff line number Diff line change
@@ -1,62 +1,95 @@
import { useState } from 'react';
import styled from 'styled-components';
import { motion, AnimatePresence } from 'framer-motion';
import CopyLogo from '@/assets/imgs/Navbar/copyLogo.svg?react';
import ShareIcon from '@/assets/imgs/Location/sharepin.svg?react'; // 모달 상단의 아이콘을 추가

interface ModalProps {
url: string;
onClose: () => void;
onCopy: () => void;
}

// HTTP 환경에서도 URL 복사 기능을 지원하는 함수
const copyToClipboard = (text: string) => {
if (navigator.clipboard) {
navigator.clipboard.writeText(text).catch(() => {
fallbackCopyTextToClipboard(text);
});
} else {
fallbackCopyTextToClipboard(text);
}
};

const fallbackCopyTextToClipboard = (text: string) => {
const textArea = document.createElement('textarea');
textArea.value = text;
document.body.appendChild(textArea);
textArea.focus();
textArea.select();
try {
document.execCommand('copy');
} catch (err) {
console.error('복사 실패', err);
}
document.body.removeChild(textArea);
};

export default function BannerMessage() {
const [isModalOpen, setIsModalOpen] = useState(false);
const [copied, setCopied] = useState(false);
// url에 따라 안에 배너 메세지 수정하는 로직 추가 필요
const handleCopy = () => {

const handleOpenModal = () => {
setIsModalOpen(true);
};

const handleCloseModal = () => {
setIsModalOpen(false);
};

const handleCopyUrl = () => {
const url = window.location.href;
navigator.clipboard.writeText(url).then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 1000);
});
copyToClipboard(url);
setCopied(true);
setTimeout(() => setCopied(false), 1000);
};

return (
<Textbox className="flex items-center justify-center gap-2 p-2 py-5 rounded-lg *:text-lg">
<div className="flex items-center justify-center gap-2 p-2 py-5 rounded-lg *:text-lg">
<CopyLogo />
<div className="relative">
<AnimatePresence>
{copied && (
<CopiedMessage
initial={{ opacity: 0, y: -10 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.5 }}
>
링크가 복사되었습니다
</CopiedMessage>
)}
</AnimatePresence>
상대방에게{' '}
<span className="text-[#2F5FDD] font-semibold underline cursor-pointer" onClick={handleCopy}>
<span className="text-[#2F5FDD] font-semibold underline cursor-pointer" onClick={handleOpenModal}>
싱크스팟 링크
</span>
를 공유해보세요!
</div>
</Textbox>

{isModalOpen && (
<Modal url={window.location.href} onClose={handleCloseModal} onCopy={handleCopyUrl} copied={copied} />
)}
</div>
);
}

const Textbox = styled.div`
width: 80%;
background: ${(props) => props.theme.bgColor};
`;

const CopiedMessage = styled(motion.div)`
position: absolute;
bottom: 150%;
left: 20%;
transform: translateX(-50%);
background-color: ${(props) => props.theme.mainColor};
color: white;
padding: 5px 10px;
border-radius: 5px;
font-size: 14px;
font-weight: 600;
display: flex;
justify-content: center;
width: max-content;
`;
const Modal: React.FC<ModalProps & { copied: boolean }> = ({ url, onClose, onCopy, copied }) => (
<div className="fixed inset-0 flex items-center justify-center bg-black bg-opacity-50 z-[90]">
<div className="bg-white rounded-2xl p-8 w-[490px] h-[490px] flex flex-col items-center shadow-lg gap-3">
<div className="size-14">
<ShareIcon />
</div>
<h2 className="text-2xl font-semibold text-[#1A3C95]">친구들에게 링크 공유하기</h2>
<p className="flex flex-col items-center text-[16px] text-gray-600 mb-4">
<span>링크를 공유하면 내가 입력한 위치에 대한</span>
<span>중간 지점 찾기 결과를 공유할 수 있어요!</span>
</p>
<div className="p-2 mb-8 text-sm break-words bg-gray-100 rounded-lg cursor-not-allowed min-h-10">{url}</div>
<div className="flex flex-col justify-center w-full gap-4 *:font-semibold">
<button className="px-4 py-2 text-white bg-blue-500 rounded-lg hover:bg-blue-400" onClick={onCopy}>
{copied ? '링크가 복사되었습니다!' : '링크 복사하기'}
</button>
<button className="px-4 py-2 text-black bg-gray-300 rounded-lg hover:bg-gray-400" onClick={onClose}>
닫기
</button>
</div>
</div>
</div>
);
10 changes: 5 additions & 5 deletions src/pages/Home/home.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import Map from '@/assets/imgs/Home/Map.svg?react';
import PinkVote from '@/assets/imgs/Home/PinkVote.svg?react';
import SpeechBubble from '@/assets/imgs/Home/speechBubble.svg?react';
import Target from '@/assets/imgs/Home/Target.svg?react';
import NextArrow from '@/assets/imgs/Home/nextArrow.svg?react';
import Tower from '@/assets/imgs/Home/Tower.svg?react';
import MiniCar from '@/assets/imgs/Home/MiniCar.svg?react';
import { ArrowLongRightIcon } from '@heroicons/react/24/solid';

interface DotProps {
num: number;
Expand Down Expand Up @@ -207,7 +207,7 @@ export default function Home() {
</div>
<div className="bg-[#AFC5FF] w-full rounded-2xl h-1/2 relative">
<motion.button
className="absolute flex items-center gap-4 px-10 py-5 text-lg font-semibold text-white transition-all cursor-pointer -top-10 left-5 bg-gradient-to-r from-cyan-500 to-blue-500 rounded-3xl"
className="absolute z-50 flex items-center gap-4 px-10 py-5 text-lg font-semibold text-white transition-all cursor-pointer -top-10 left-5 bg-gradient-to-r from-cyan-500 to-blue-500 rounded-3xl"
onClick={handleIconClick}
whileHover={{
background: '#FFFFFF',
Expand All @@ -227,10 +227,10 @@ export default function Home() {
background: 'linear-gradient(to right, #06b6d4, #3b82f6)',
}}
>
지금 바로 중간지점을 찾아보세요! <NextArrow className="size-6" />
지금 바로 중간지점을 찾아보세요! <ArrowLongRightIcon className="size-6" />
</motion.button>
<SpeechBubble className="absolute -top-40 left-64" />
<h1 className="absolute font-semibold text-md text-white -top-[95px] left-[355px]">
<SpeechBubble className="absolute -top-[270px] left-72 size-[380px]" />
<h1 className="absolute font-semibold text-md text-white -top-[100px] left-[355px]">
여기를 눌러 싱크스팟을 사용해 보세요!
</h1>
<div className="flex items-center gap-5 mt-20 ml-14 *:text-xl text-[#1A3C95]">
Expand Down
126 changes: 68 additions & 58 deletions src/pages/Login/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ import { fetchLogin } from '@/apis/login';
import LoginLogo from '@/assets/imgs/loginLogo.svg?react';
import { yupResolver } from '@hookform/resolvers/yup';
import { schema } from '@/types/Login';
import { toast, ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import {
FROM_ALONE_CREATE_VOTE_PLACE,
FROM_ALONE_CREATE_VOTE_TIME,
Expand Down Expand Up @@ -54,66 +56,75 @@ export default function Login() {
const { mutate: userLogin } = useMutation({
mutationFn: fetchLogin,
onSuccess: (data: any) => {
localStorage.setItem('accessToken', data.data.data.accessToken);
localStorage.setItem('refreshToken', data.data.data.refreshToken);
localStorage.setItem('roomId', roomId!);
setLoginState(true);
switch (from) {
case FROM_ALONE_RESULT:
navigate(`/page/a/results/${roomId}`);
break;
case FROM_EACH_RESULT:
navigate(`/page/e/results/${roomId}`);
break;
case FROM_ENTER_ALONE:
navigate(`/page/alone/${roomId}`);
break;
case FROM_ENTER_EACH:
navigate(`/page/each/${roomId}`);
break;
case FROM_ALONE_CREATE_VOTE_PLACE:
navigate(`/page/a/create/place-vote-room/${roomId}`);
break;
case FROM_ALONE_PLACE_VOTE:
navigate(`/page/a/place-vote/${roomId}`);
break;
case FROM_ALONE_PLACE_VOTE_RESULT:
navigate(`/page/a/place-vote/results/${roomId}`);
break;
case FROM_EACH_CREATE_VOTE_PLACE:
navigate(`/page/e/create/place-vote-room/${roomId}`);
break;
case FROM_EACH_PLACE_VOTE:
navigate(`/page/e/place-vote/${roomId}`);
break;
case FROM_EACH_PLACE_VOTE_RESULT:
navigate(`/page/e/place-vote/results/${roomId}`);
break;
case FROM_ALONE_CREATE_VOTE_TIME:
navigate(`/page/a/create/time-vote-room/${roomId}`);
break;
case FROM_ALONE_TIME_VOTE:
navigate(`/page/a/time-vote/${roomId}`);
break;
case FROM_ALONE_TIME_VOTE_RESULT:
navigate(`/page/a/time-vote/results/${roomId}`);
break;
case FROM_EACH_CREATE_VOTE_TIME:
navigate(`/page/e/create/time-vote-room/${roomId}`);
break;
case FROM_EACH_TIME_VOTE:
navigate(`/page/e/time-vote/${roomId}`);
break;
case FROM_EACH_TIME_VOTE_RESULT:
navigate(`/page/e/time-vote/results/${roomId}`);
break;
default:
navigate('/');
break;
if (data.data.data) {
localStorage.setItem('accessToken', data.data.data.accessToken);
localStorage.setItem('refreshToken', data.data.data.refreshToken);
localStorage.setItem('roomId', roomId!);
setLoginState(true);
switch (from) {
case FROM_ALONE_RESULT:
navigate(`/page/a/results/${roomId}`);
break;
case FROM_EACH_RESULT:
navigate(`/page/e/results/${roomId}`);
break;
case FROM_ENTER_ALONE:
navigate(`/page/alone/${roomId}`);
break;
case FROM_ENTER_EACH:
navigate(`/page/each/${roomId}`);
break;
case FROM_ALONE_CREATE_VOTE_PLACE:
navigate(`/page/a/create/place-vote-room/${roomId}`);
break;
case FROM_ALONE_PLACE_VOTE:
navigate(`/page/a/place-vote/${roomId}`);
break;
case FROM_ALONE_PLACE_VOTE_RESULT:
navigate(`/page/a/place-vote/results/${roomId}`);
break;
case FROM_EACH_CREATE_VOTE_PLACE:
navigate(`/page/e/create/place-vote-room/${roomId}`);
break;
case FROM_EACH_PLACE_VOTE:
navigate(`/page/e/place-vote/${roomId}`);
break;
case FROM_EACH_PLACE_VOTE_RESULT:
navigate(`/page/e/place-vote/results/${roomId}`);
break;
case FROM_ALONE_CREATE_VOTE_TIME:
navigate(`/page/a/create/time-vote-room/${roomId}`);
break;
case FROM_ALONE_TIME_VOTE:
navigate(`/page/a/time-vote/${roomId}`);
break;
case FROM_ALONE_TIME_VOTE_RESULT:
navigate(`/page/a/time-vote/results/${roomId}`);
break;
case FROM_EACH_CREATE_VOTE_TIME:
navigate(`/page/e/create/time-vote-room/${roomId}`);
break;
case FROM_EACH_TIME_VOTE:
navigate(`/page/e/time-vote/${roomId}`);
break;
case FROM_EACH_TIME_VOTE_RESULT:
navigate(`/page/e/time-vote/results/${roomId}`);
break;
default:
navigate('/');
break;
}
} else {
toast.error('로그인 정보가 올바르지 않습니다!', {
position: 'top-center',
}); // 로그인 실패 시 토스트 메시지
}
},
onError: (error) => {
console.log('로그인 과정 에러', error);
toast.error('로그인 중 문제가 발생했습니다!', {
position: 'top-center',
}); // 에러 발생 시 토스트 메시지
},
});

Expand Down Expand Up @@ -159,15 +170,13 @@ export default function Login() {
className="w-full py-2 transition bg-gray-100 border-none outline-none focus:ring-2 ring-indigo-100 focus:outline-none"
/>
{errors.name && <span className="font-semibold text-red-500">{errors.name.message}</span>}

<input
{...register('pw')}
type="password"
placeholder="비밀번호"
className="w-full py-2 transition bg-gray-100 border-none focus:ring-2 ring-indigo-100 focus:outline-none"
/>
{errors.pw && <span className="font-semibold text-red-500">{errors.pw.message}</span>}

<button
type="submit"
className={`w-full min-h-10 ${isValid ? 'primary-btn' : 'bg-gray-50 cursor-not-allowed'} disabled:bg-neutral-400 disabled:text-neutral-300 disabled:cursor-not-allowed`}
Expand All @@ -176,6 +185,7 @@ export default function Login() {
{formLoading ? '잠시만 기다려 주세요...' : '사용자등록'}
</button>
</form>
<ToastContainer />
</div>
);
}

0 comments on commit 7a2204e

Please sign in to comment.