Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[feat/#58] 의견보내기 및 약관 관련 링크 연결 #94

Merged
merged 1 commit into from
Sep 26, 2024
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: 1 addition & 0 deletions src/api/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export * from "./auth"
export * from "./snapshot"
export * from "./group"
export * from "./report"
29 changes: 29 additions & 0 deletions src/api/report.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import axiosInstance from "./axiosInstance"

interface ReportResData {
data: {
id: number
uid: number
email: string
type: string
title: string
content: string
createdAt: string
modifiedAt: string
}
}

interface ReportParam {
email: string
title: string
content: string
}

export const requestSendReportAPI = async (param: ReportParam): Promise<ReportResData> => {
try {
const res = await axiosInstance.post(`/discussion`, { ...param, type: "QNA" })
return res.data
} catch (e) {
throw e
}
}
2 changes: 2 additions & 0 deletions src/components/Modal/Modals.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import CreateCrewModal from "./CreateCrewModal"
import GoodPostureGuidePopupModal from "./GoodPostureGuideModal"
import InviteCrewModal from "./InviteCrewModal"
import JoinCrewModal from "./JoinCrewModal"
import ReportModal from "./ReportModal"
import ToWithdrawModal from "./ToWithdrawModal"
import WithdrawCrewModal from "./WithdrawCrewModal"

Expand All @@ -15,6 +16,7 @@ export const modals = {
withdrawCrewModal: WithdrawCrewModal,
ToWithdrawModal: ToWithdrawModal,
postureGuideModal: GoodPostureGuidePopupModal,
reportModal: ReportModal,
}

const Modals = (): React.ReactNode => {
Expand Down
117 changes: 117 additions & 0 deletions src/components/Modal/ReportModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import { requestSendReportAPI } from "@/api"
import { ModalProps } from "@/contexts/ModalsContext"
import ModalContainer from "@components/ModalContainer"
import { useState } from "react"

const ReportModal = (props: ModalProps): React.ReactElement => {
const { onClose, onSubmit } = props

const [title, setTitle] = useState<string>("")
const [email, setEmail] = useState<string>("")
const [isValidEmail, setIsValidEmail] = useState(false)
const [description, setDescription] = useState<string>("")

const onChangeName = (e: React.ChangeEvent<HTMLInputElement>): void => {
setTitle(e.target.value)
}

const onChangeDescription = (e: React.ChangeEvent<HTMLTextAreaElement>): void => {
if (e.target.value.length <= 500) setDescription(e.target.value)
}

const isValidForm = (): boolean => {
return Boolean(title.trim() && email.trim() && description.trim()) && isValidEmail
}

const handleSubmit = (): void => {
if (!isValidForm()) {
return
}

requestSendReportAPI({
title,
email,
content: description,
}).then(({ data }) => {
if (onSubmit && typeof onSubmit === "function") onSubmit()
})
}

const onChangeEmail = (event: any) => {
setEmail(event.target.value.trim())

const emailRegex = /^[\w-\.]+@([\w-]+)\.?([\w-]+)\.+[\w-]{2,4}$/
const validEmail = emailRegex.test(event.target.value)
setIsValidEmail(validEmail)
}

return (
<ModalContainer onClose={onClose}>
<div className="flex flex-col items-center">
{/* header */}
<div className="mb-10 flex items-center gap-4">
<div className="text-xl font-bold text-zinc-900">의견 보내기</div>
</div>

<div className="mb-6 flex w-full flex-col text-[15px]">
{/* crew owner */}
<div className="mb-4 flex flex-col gap-1">
<div className="font-semibold text-[#1A75FF]">제목</div>
<div className="mb-1 flex gap-4">
<input
type="text"
className="w-full rounded-xl border border-gray-200 border-gray-200 px-3 py-2 outline-none"
value={title}
onChange={onChangeName}
placeholder="의견 제목을 입력해주세요."
/>
</div>
</div>

<div className="mb-4 flex flex-col gap-1">
<div className="font-semibold text-[#1A75FF]">이메일</div>
<div className="mb-1 flex gap-4">
<input
type="email"
className="w-full rounded-xl border border-gray-200 border-gray-200 px-3 py-2 outline-none"
value={email}
onChange={onChangeEmail}
placeholder="이메일을 입력해주세요."
/>
</div>
{email && !isValidEmail && (
<div className="h-[24px] text-sm text-orange-400">올바른 이메일을 입력해주세요.</div>
)}
</div>

{/* crew description */}
<div className="flex flex-col gap-1">
<div className="text-[15px] font-semibold text-[#1A75FF]">상세 내용</div>
<div>
<textarea
className={`h-[140px] w-full resize-none rounded-xl border border-gray-200 p-3 outline-none`}
value={description}
onChange={onChangeDescription}
placeholder="상세 내용을 작성해주세요."
/>
<div className="text-end text-[13px] text-zinc-400">{`${description.length}/500`}</div>
</div>
</div>
</div>

{/* button */}
<button
className={`w-[256px] rounded-[40px] px-10 py-3 text-base font-semibold text-white ${
isValidForm() ? "bg-[#1A75FF]" : "bg-gray-200"
}`}
onClick={handleSubmit}
disabled={!isValidForm()}
>
의견 보내기
</button>
</div>
</ModalContainer>
)
}

export default ReportModal
23 changes: 21 additions & 2 deletions src/components/SideNav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import CrewIcon from "@assets/icons/side-nav-crew-icon.svg?react"
import MonitoringIcon from "@assets/icons/side-nav-monitor-icon.svg?react"
import { useMemo } from "react"
import { Link, useLocation, useNavigate } from "react-router-dom"
import { useModals } from "@/hooks/useModals"
import { modals } from "./Modal/Modals"

const navItems = [
{
Expand All @@ -31,6 +33,7 @@ export default function SideNav(): React.ReactElement {
const location = useLocation()
const logout = useAuthStore((state) => state.logout)
const navigate = useNavigate()
const { openModal } = useModals()

const logoutHandler = (): void => {
const clearUser = useAuthStore.persist.clearStorage
Expand All @@ -49,8 +52,24 @@ export default function SideNav(): React.ReactElement {

const footerLinks = useMemo(
() => [
{ label: "이용약관", link: "", onClick: () => {} },
{ label: "의견보내기", link: "", onClick: () => {} },
{
label: "이용약관",
link: "",
onClick: () => {
window.open("https://swjg3gi.notion.site/7c13aba015654e6f8e1acd300b440526?pvs=4", "_blank")
},
},
{
label: "의견보내기",
link: "",
onClick: () => {
openModal(modals.reportModal, {
onSubmit: () => {
// navigate(RoutePath.MYCREW)
},
})
},
},
{ label: "로그아웃", link: "", onClick: logoutHandler },
],
[logoutHandler]
Expand Down
8 changes: 6 additions & 2 deletions src/pages/HomePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,12 @@ const HomePage: React.FC = () => {
<div className="flex items-center text-[#D9D9D9]">
<div className="mr-20 text-2xl font-bold">ALIGN LAB</div>
<div className="flex gap-20 text-sm">
<div>개인정보처리방침</div>
<div>이용약관</div>
<a href="https://swjg3gi.notion.site/89966f39e24a442a8eee5b1f91c4fde7" target="_blank">
<div>개인정보처리방침</div>
</a>
<a href="https://swjg3gi.notion.site/7c13aba015654e6f8e1acd300b440526?pvs=4" target="_blank">
<div>이용약관</div>
</a>
</div>
</div>
<div className="mt-10 text-xs font-normal text-[#9D9DA2]">Copyright all reserved @2024</div>
Expand Down
Loading