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
12 changes: 8 additions & 4 deletions src/app/(layout)/advice/_components/AdviceEditor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@ import RecommendTemplates from '../RecommendTemplates';
import IconHelp from '@/assets/icons/icon-help.svg';
import { usePostAdvice } from '@/hooks/models/usePostAdvice';
import { useSpellCheck } from '@/hooks/models/usePostSpellCheck';
import { useAuth } from '@/hooks/useAuth';

export default function AdviceEditor() {
const { currentTemplate } = useTemplateStore();
const { requireAuth } = useAuth();
const [draftContent, setDraftContent] = useState(currentTemplate?.content || '');
const [tags, setTags] = useState<string[]>([]);
const [aiMode, setAiMode] = useState(true);
Expand Down Expand Up @@ -52,10 +54,12 @@ export default function AdviceEditor() {

const handleSubmit = () => {
if (aiMode) {
mutate({
content: draftContent,
tags: tags.filter((tag) => tag.trim() !== ''),
});
if (requireAuth()) {
mutate({
content: draftContent,
tags: tags.filter((tag) => tag.trim() !== ''),
});
}
} else {
spellCheckMutate({
content: draftContent,
Expand Down
32 changes: 29 additions & 3 deletions src/app/(layout)/advice/_components/RecommendTemplates/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,20 @@ import Card from '@/components/ui/Card';
import { TemplateType } from '@/types';
import { useTemplatesRecommendation } from '@/hooks/template/useTemplatesRecommendation';
import { useTemplatesLikes } from '@/hooks/template/useTemplateLikes';
import { useAuth } from '@/hooks/useAuth';
import { checkAuth } from '@/utils/checkAuth';

export default function RecommendTemplates() {
const { requireAuth } = useAuth();
const [isAuthenticated, setIsAuthenticated] = useState(() => {
if (typeof window !== 'undefined') {
return checkAuth();
}
return false;
});

const { data: recommendData } = useTemplatesRecommendation();
const { data: likeData } = useTemplatesLikes();
const { data: likeData } = useTemplatesLikes({ enabled: isAuthenticated });

const asideList = [
{ label: 'recommend', text: '추천 템플릿' },
Expand All @@ -19,12 +29,28 @@ export default function RecommendTemplates() {
const [asideState, setAsideState] = useState('recommend');
const [templates, setTemplates] = useState<TemplateType[]>([]);

useEffect(() => {
setIsAuthenticated(checkAuth());
}, []);

const handleAside = (label: string) => {
if (label === 'like' && !requireAuth()) {
return;
}
setAsideState(label);
};

useEffect(() => {
const response = asideState === 'recommend' ? recommendData : likeData;
let response;

if (asideState === 'recommend') {
response = recommendData;
} else if (asideState === 'like' && isAuthenticated) {
response = likeData;
} else {
response = null;
}

const templates =
response?.templates.map((templates) => ({
title: templates.title,
Expand All @@ -36,7 +62,7 @@ export default function RecommendTemplates() {
})) ?? [];

setTemplates(templates);
}, [recommendData, likeData, asideState]);
}, [recommendData, likeData, asideState, isAuthenticated]);

return (
<section className="z-10 flex">
Expand Down
19 changes: 19 additions & 0 deletions src/assets/icons/image-login.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 19 additions & 5 deletions src/components/ui/Header/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@

import { useEffect, useState } from 'react';
import Link from 'next/link';
import { useRouter } from 'next/navigation';
import { usePathname } from 'next/navigation';
import { cn } from '@/lib/utils';
import { useAuth } from '@/hooks/useAuth';
import { Button } from '../Button';
import Logo from '@/assets/logo.svg';

export default function Header() {
const pathname = usePathname();
const router = useRouter();
const [isLogin, setIsLogin] = useState(false);
const { requireAuth } = useAuth();

const menus = [
{ label: '조언받기', href: '/advice' },
Expand All @@ -21,7 +25,7 @@ export default function Header() {
const token = localStorage.getItem('token');
const user = localStorage.getItem('user');
setIsLogin(!!(token && user));
}, []);
}, [isLogin]);

return (
<header className="bg-layout-grey1 mx-auto mb-[100px] flex min-w-screen items-center justify-between px-24 py-3">
Expand All @@ -33,13 +37,21 @@ export default function Header() {
{menus.map((menu) => {
const isActive = pathname.startsWith(menu.href);
return (
<Link
<button
key={menu.href}
href={menu.href}
onClick={() => {
if (menu.label === '보관함') {
if (requireAuth()) {
router.push(menu.href);
}
} else {
router.push(menu.href);
}
}}
className={cn('text-layout-grey5 button-lg', isActive && 'text-layout-grey6')}
>
{menu.label}
</Link>
</button>
);
})}
</nav>
Expand All @@ -54,7 +66,9 @@ export default function Header() {
variant="grey"
size="small"
onClick={() => {
alert('로그아웃!');
window.localStorage.removeItem('token');
window.localStorage.removeItem('user');
window.location.reload();
}}
>
로그아웃
Expand Down
41 changes: 41 additions & 0 deletions src/components/ui/Modal/LoginModal/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useRouter } from 'next/navigation';
import { useLoginModalStore } from '@/stores/useLoginModal';
import { Spacing } from '../../Spacing';
import { Button } from '../../Button';
import IconClose from '@/assets/icons/icon-close.svg';
import ImageLogin from '@/assets/icons/image-login.svg';

export default function LoginModal() {
const router = useRouter();

const { isLoginOpen, closeLoginModal } = useLoginModalStore();

if (!isLoginOpen) return null;

return (
<section className="bg-layout-white flex h-[440px] w-[780px] flex-col items-center justify-center rounded-lg p-6">
<button onClick={closeLoginModal} className="flex w-full justify-end">
<IconClose />
</button>
<ImageLogin />
<Spacing size={8} />
<div className="body-lg text-layout-grey5">이 기능은 로그인 후에 사용할 수 있습니다.</div>
<Spacing size={12} />
<div className="title-lg">로그인하고 더 많은 기능을 누려보세요!</div>
<Spacing size={48} />
<section className="flex gap-2">
<Button state="line" onClick={closeLoginModal}>
다음에 하기
</Button>
<Button
onClick={() => {
router.push('/login');
}}
>
로그인하기
</Button>
</section>
<Spacing size={25} />
</section>
);
}
12 changes: 11 additions & 1 deletion src/components/ui/Modal/ModalContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,19 @@

import { useModalStore } from '@/stores/useModalStore';
import { useUnsaveModalStore } from '@/stores/useUnsaveModalStore';
import { useLoginModalStore } from '@/stores/useLoginModal';
import ViewModal from './ViewModal';
import EditModal from './EditModal';
import UsingModal from './UsingModal';
import ProfileModal from './ProfileModal';
import UnSaveModal from './UnsaveModal';
import LoginModal from './LoginModal';
import { useEffect } from 'react';

export default function ModalContainer() {
const { currentModal, draftTitle, draftContent, draftTags, selectedTemplateId } = useModalStore();
const { isUnsaveOpen } = useUnsaveModalStore();
const { isLoginOpen} = useLoginModalStore();

useEffect(() => {
if (currentModal) {
Expand All @@ -25,7 +28,7 @@ export default function ModalContainer() {
};
}, [currentModal]);

if (!currentModal && !isUnsaveOpen) return null;
if (!currentModal && !isUnsaveOpen && !isLoginOpen) return null;

return (
<>
Expand Down Expand Up @@ -57,6 +60,13 @@ export default function ModalContainer() {
</div>
</div>
)}
{isLoginOpen && (
<div className="fixed inset-0 z-[1010] flex items-center justify-center bg-black/40">
<div onClick={(e) => e.stopPropagation()}>
<LoginModal />
</div>
</div>
)}
</>
);
}
33 changes: 21 additions & 12 deletions src/components/ui/Modal/ViewModal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import clsx from 'clsx';
import { useRouter } from 'next/navigation';
import { useModalStore } from '@/stores/useModalStore';
import { useTemplateStore } from '@/stores/useTemplateStore';
import { useAuth } from '@/hooks/useAuth';
import { getTemplateDetail, TemplateDetail } from '@/services/template/getTemplateDetail';
import { Spacing } from '../../Spacing';
import { Button } from '../../Button';
Expand All @@ -23,6 +24,8 @@ export default function ViewModal() {

const { selectedTemplateId, openModal, closeModal } = useModalStore();
const { setCurrentTemplate } = useTemplateStore();
const { requireAuth } = useAuth();

const [template, setTemplate] = useState<TemplateDetail | null>(null);
const [folderId, setFolderId] = useState<number>();
const [loading, setLoading] = useState(true);
Expand Down Expand Up @@ -54,13 +57,15 @@ export default function ViewModal() {
if (loading || !template) return <div className="p-8 text-center">불러오는 중...</div>;

const handleCilckUse = () => {
closeModal();
openModal('using', {
templateId: template.templateId,
draftTitle: template.title,
draftContent: template.content,
draftTags: template.tags,
});
if (requireAuth()) {
closeModal();
openModal('using', {
templateId: template.templateId,
draftTitle: template.title,
draftContent: template.content,
draftTags: template.tags,
});
}
};

const handleClickEdit = (template: TemplateDetail) => {
Expand All @@ -80,7 +85,9 @@ export default function ViewModal() {
};

const handleDropdown = () => {
setDropdown((prev) => !prev);
if (requireAuth()) {
setDropdown((prev) => !prev);
}
};

const handleCopyClipBoard = (text: string) => {
Expand All @@ -98,10 +105,12 @@ export default function ViewModal() {
};

const handleAuthor = () => {
closeModal();
openModal('profile', {
templateId: template.templateId,
});
if (requireAuth()) {
closeModal();
openModal('profile', {
templateId: template.templateId,
});
}
};

return (
Expand Down
3 changes: 2 additions & 1 deletion src/hooks/template/useTemplateLikes.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { getTemplateLikes } from '@/services/template/getTemplateLikes';
import { useQuery } from '@tanstack/react-query';

export const useTemplatesLikes = () => {
export const useTemplatesLikes = (options?: { enabled?: boolean }) => {
return useQuery({
queryKey: ['templates', 'likes'],
queryFn: () => getTemplateLikes(),
enabled: options?.enabled ?? true,
});
};
19 changes: 19 additions & 0 deletions src/hooks/useAuth.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { checkAuth } from '@/utils/checkAuth';
import { useLoginModalStore } from '@/stores/useLoginModal';

export const useAuth = () => {
const { openLoginModal } = useLoginModalStore();

const requireAuth = (): boolean => {
const isAuthenticated = checkAuth();

if (!isAuthenticated) {
openLoginModal();
return false;
}

return true;
};

return { requireAuth };
};
13 changes: 13 additions & 0 deletions src/stores/useLoginModal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { create } from 'zustand';

interface LoginModalState {
isLoginOpen: boolean;
openLoginModal: () => void;
closeLoginModal: () => void;
}

export const useLoginModalStore = create<LoginModalState>((set) => ({
isLoginOpen: false,
openLoginModal: () => set({ isLoginOpen: true }),
closeLoginModal: () => set({ isLoginOpen: false }),
}));
8 changes: 8 additions & 0 deletions src/utils/checkAuth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export const checkAuth = (): boolean => {
if (typeof window === 'undefined') return false;

const token = localStorage.getItem('token');
const user = localStorage.getItem('user');

return !!(token && user);
};