From 1746c9174228b8b37fbd32f9d51bc02dd7907721 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Thu, 8 May 2025 17:55:24 +0900 Subject: [PATCH] feat: integrate EdgeProvider for alert management and add Suitable components for roof material compatibility checks --- src/app/layout.tsx | 25 +++--- src/app/suitable/layout.tsx | 24 +++++ src/app/suitable/page.tsx | 4 +- src/components/popup/SuitableDetailPopup.tsx | 32 +++++++ src/components/suitable/Suitable.tsx | 87 +++++++++++++++++++ src/components/suitable/SuitableCheckData.tsx | 68 +++++++++++++++ src/components/suitable/SuitableNoData.tsx | 15 ++++ src/components/ui/Main.tsx | 22 +---- src/components/ui/PopupController.tsx | 7 ++ src/components/ui/common/Alert.tsx | 24 +++++ src/components/ui/common/DoubleBtnAlert.tsx | 21 +++++ src/providers/EdgeProvider.tsx | 64 ++++++++++++++ src/store/popupController.ts | 36 ++++++++ 13 files changed, 397 insertions(+), 32 deletions(-) create mode 100644 src/app/suitable/layout.tsx create mode 100644 src/components/popup/SuitableDetailPopup.tsx create mode 100644 src/components/suitable/Suitable.tsx create mode 100644 src/components/suitable/SuitableCheckData.tsx create mode 100644 src/components/suitable/SuitableNoData.tsx create mode 100644 src/components/ui/common/Alert.tsx create mode 100644 src/components/ui/common/DoubleBtnAlert.tsx create mode 100644 src/providers/EdgeProvider.tsx diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 4b043a8..e7fbcf6 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -1,6 +1,7 @@ import type { Metadata } from 'next' import ReactQueryProviders from '@/providers/ReactQueryProvider' +import EdgeProvider from '@/providers/EdgeProvider' import PopupController from '@/components/ui/PopupController' import '@/styles/style.scss' @@ -22,17 +23,19 @@ interface RootLayoutProps { export default async function RootLayout({ children, header, footer, floatBtn }: RootLayoutProps): Promise { return ( - - -
- {header} - {children} - {footer} - {floatBtn} -
- - - + + + +
+ {header} + {children} + {footer} + {floatBtn} +
+ + + +
) } diff --git a/src/app/suitable/layout.tsx b/src/app/suitable/layout.tsx new file mode 100644 index 0000000..25e2615 --- /dev/null +++ b/src/app/suitable/layout.tsx @@ -0,0 +1,24 @@ +import { ReactNode } from 'react' + +interface SuitableLayoutProps { + children: ReactNode +} + +export default function layout({ children }: SuitableLayoutProps) { + return ( + <> +
+
+
+
+
この適合表は参考資料として使用してください.
+
詳細やお問い合わせは1:1お問い合わせをご利用ください.
+
屋根材の選択or屋根材名を直接入力してください.
+
+
+ {children} +
+
+ + ) +} diff --git a/src/app/suitable/page.tsx b/src/app/suitable/page.tsx index 10e60d6..fe9d9c1 100644 --- a/src/app/suitable/page.tsx +++ b/src/app/suitable/page.tsx @@ -1,7 +1,9 @@ +import Suitable from '@/components/suitable/Suitable' + export default function page() { return ( <> -

지붕재 적합성

+ ) } diff --git a/src/components/popup/SuitableDetailPopup.tsx b/src/components/popup/SuitableDetailPopup.tsx new file mode 100644 index 0000000..59b7838 --- /dev/null +++ b/src/components/popup/SuitableDetailPopup.tsx @@ -0,0 +1,32 @@ +export default function SuitableDetailPopup() { + return ( +
+
+
+
+
+
+
+ +
+
屋根材適合性詳細
+
+ +
+
+
+
+
+
アースティ40
+
+ +
+
+
+
+
+
+
+
+ ) +} diff --git a/src/components/suitable/Suitable.tsx b/src/components/suitable/Suitable.tsx new file mode 100644 index 0000000..5120aa3 --- /dev/null +++ b/src/components/suitable/Suitable.tsx @@ -0,0 +1,87 @@ +'use client' + +import { useState } from 'react' +import SuitableCheckData from './SuitableCheckData' +import SuitableNoData from './SuitableNoData' + +export default function Suitable() { + const [reference, setReference] = useState(false) + + return ( +
+
+ +
+
+
+ + +
+
+
+
+
+
凡例
+
+ +
+
+
    +
  • +
    + 設置可能 +
    +
  • +
  • +
    + 設置可能 +
    +
  • +
  • +
    + 設置可能 +
    +
  • +
  • +
    + 設置可能 +
    +
  • +
+
+ {/* checkData */} + {/* 데이터 없을경우 버튼 영역 안보여야함 */} + + + + +
+ {/* 데이터 없을경우 버튼 영역 안보여야함 */} +
+
+ +
+
+ +
+
+ +
+
+ {/* 검색기록 없을떄 위에 두 영역 안보이고 이 부분만 보여야 함*/} + {/* */} +
+ ) +} diff --git a/src/components/suitable/SuitableCheckData.tsx b/src/components/suitable/SuitableCheckData.tsx new file mode 100644 index 0000000..2cef53b --- /dev/null +++ b/src/components/suitable/SuitableCheckData.tsx @@ -0,0 +1,68 @@ +'use client' + +export default function SuitableCheckData() { + return ( + <> +
+
+
+ + +
+
+ +
+
+
    +
  • +
    +
    + + +
    +
    + + +
    +
    +
  • +
  • +
    +
    + + +
    +
    + + +
    +
    +
  • +
  • +
    +
    + + +
    +
    + + +
    +
    +
  • +
  • +
    +
    + + +
    +
    + +
    +
    +
  • +
+
+ + ) +} diff --git a/src/components/suitable/SuitableNoData.tsx b/src/components/suitable/SuitableNoData.tsx new file mode 100644 index 0000000..1245fbf --- /dev/null +++ b/src/components/suitable/SuitableNoData.tsx @@ -0,0 +1,15 @@ +export default function SuitableNoData() { + return ( + <> +
+ 検索結果はありません。 + 屋根材適合性表にない製品の情報を入力してください。 今後返信いたします。 + + + +
+ + ) +} diff --git a/src/components/ui/Main.tsx b/src/components/ui/Main.tsx index 37de8e7..5f6eff4 100644 --- a/src/components/ui/Main.tsx +++ b/src/components/ui/Main.tsx @@ -1,27 +1,9 @@ 'use client' -import { useHeaderStore } from '@/store/header' -import { useSideNavState } from '@/store/sideNavState' -import { usePathname, useRouter } from 'next/navigation' -import { useEffect } from 'react' +import { useRouter } from 'next/navigation' export default function Main() { const router = useRouter() - const pathname = usePathname() - const { setBackBtn } = useHeaderStore() - const { reset } = useSideNavState() - - /** - * 헤더 뒤로가기 버튼 컨트롤 - * 사이드바 초기화 컨트롤 - */ - useEffect(() => { - if (pathname === '/') { - setBackBtn(false) - } - //사이드바 초기화 - reset() - }, [pathname]) return ( <> @@ -30,7 +12,7 @@ export default function Main() {
屋根材の照会
ご使用の屋根材の適合性をご確認いただけます
-
diff --git a/src/components/ui/PopupController.tsx b/src/components/ui/PopupController.tsx index e221d6a..0bf79e7 100644 --- a/src/components/ui/PopupController.tsx +++ b/src/components/ui/PopupController.tsx @@ -1,8 +1,12 @@ 'use client' import { usePopupController } from '@/store/popupController' + import MemberInfomationPopup from '../popup/MemberInformationPopup' import ZipCodePopup from '../popup/ZipCodePopup' +import Alert from './common/Alert' +import DoubleBtnAlert from './common/DoubleBtnAlert' +import SuitableDetailPopup from '../popup/SuitableDetailPopup' export default function PopupController() { const popupController = usePopupController() @@ -11,6 +15,9 @@ export default function PopupController() { <> {popupController.memberInfomationPopup && } {popupController.zipCodePopup && } + {popupController.alert && } + {popupController.alert2 && } + {popupController.suitableDetailPopup && } ) } diff --git a/src/components/ui/common/Alert.tsx b/src/components/ui/common/Alert.tsx new file mode 100644 index 0000000..96dd5ca --- /dev/null +++ b/src/components/ui/common/Alert.tsx @@ -0,0 +1,24 @@ +'use client' + +import { usePopupController } from '@/store/popupController' + +export default function Alert() { + const { alertMsg, alertBtn } = usePopupController() + + return ( +
+
+
+
{alertMsg}
+
+
+ +
+
+
+
+
+ ) +} diff --git a/src/components/ui/common/DoubleBtnAlert.tsx b/src/components/ui/common/DoubleBtnAlert.tsx new file mode 100644 index 0000000..34af34b --- /dev/null +++ b/src/components/ui/common/DoubleBtnAlert.tsx @@ -0,0 +1,21 @@ +import React from 'react' + +export default function DoubleBtnAlert() { + return ( +
+
+
+
本当に削除しますか?
+
+
+ +
+
+ +
+
+
+
+
+ ) +} diff --git a/src/providers/EdgeProvider.tsx b/src/providers/EdgeProvider.tsx new file mode 100644 index 0000000..2ca2811 --- /dev/null +++ b/src/providers/EdgeProvider.tsx @@ -0,0 +1,64 @@ +'use client' + +import { useHeaderStore } from '@/store/header' +import { usePopupController } from '@/store/popupController' +import { useSideNavState } from '@/store/sideNavState' +import { usePathname } from 'next/navigation' +import { useEffect } from 'react' + +declare global { + interface Window { + alert2: (msg: string, alert2BtnYes?: () => void, alert2BtnNo?: () => void) => void + } +} + +export default function EdgeProvider({ children }: React.PropsWithChildren) { + const pathname = usePathname() + const { setBackBtn } = useHeaderStore() + const { reset } = useSideNavState() + const { setAlertMsg, setAlertBtn, setAlert, setAlert2, setAlert2BtnYes, setAlert2BtnNo } = usePopupController() + + const alertFunc = (msg: string, alertBtn: Function) => { + console.log('🚀 ~ alertFunc ~ msg:', msg) + setAlertMsg(msg) + setAlertBtn(alertBtn) + setAlert(true) + } + /** + * alert2 함수 + * @param msg alert 메시지 + * @param alertBtn2Yes alert 확인 버튼 클릭시 실행되는 함수 + * @param alertBtn2No alert 취소 버튼 클릭시 실행되는 함수 + */ + const alertFunc2 = (msg: string, alertBtn2Yes: Function, alertBtn2No: Function) => { + console.log('🚀 ~ alertFunc ~ msg:', msg) + setAlertMsg(msg) + setAlert2BtnYes(alertBtn2Yes) + setAlert2BtnNo(alertBtn2No) + setAlert2(true) + } + + useEffect(() => { + window.alert = function (msg, alertBtn = () => setAlert(false)) { + alertFunc(msg, alertBtn) + } + + window.alert2 = function (msg, alert2BtnYes = () => setAlert2(false), alert2BtnNo = () => setAlert2(false)) { + alertFunc2(msg, alert2BtnYes, alert2BtnNo) + } + }, []) + + /** + * 헤더 뒤로가기 버튼 컨트롤 + * 사이드바 초기화 컨트롤 + */ + useEffect(() => { + if (pathname === '/') { + setBackBtn(false) + } + //사이드바 초기화 + reset() + }, [pathname]) + + return <>{children} +} diff --git a/src/store/popupController.ts b/src/store/popupController.ts index 2a83120..611bb55 100644 --- a/src/store/popupController.ts +++ b/src/store/popupController.ts @@ -3,23 +3,59 @@ import { create } from 'zustand' type PoupControllerState = { memberInfomationPopup: boolean zipCodePopup: boolean + alertMsg: string + setAlertMsg: (value: string) => void + alert: boolean + alertBtn: Function + alert2: boolean + alert2BtnYes: Function + alert2BtnNo: Function setMemberInfomationPopup: (value: boolean) => void setZipCodePopup: (value: boolean) => void + setAlert: (value: boolean) => void + setAlertBtn: (value: Function) => void + setAlert2: (value: boolean) => void + setAlert2BtnYes: (value: Function) => void + setAlert2BtnNo: (value: Function) => void + suitableDetailPopup: boolean + setSuitableDetailPopup: (value: boolean) => void + reset: () => void } type InitialState = { memberInfomationPopup: boolean zipCodePopup: boolean + alertMsg: string + alert: boolean + alertBtn: Function + alert2: boolean + alert2BtnYes: Function + alert2BtnNo: Function + suitableDetailPopup: boolean } const initialState: InitialState = { memberInfomationPopup: false, zipCodePopup: false, + alertMsg: '', + alert: false, + alertBtn: () => {}, + alert2: false, + alert2BtnYes: () => {}, + alert2BtnNo: () => {}, + suitableDetailPopup: false, } export const usePopupController = create((set) => ({ ...initialState, setMemberInfomationPopup: (value: boolean) => set((state) => ({ ...state, memberInfomationPopup: value })), setZipCodePopup: (value: boolean) => set((state) => ({ ...state, zipCodePopup: value })), + setAlertMsg: (value: string) => set((state) => ({ ...state, alertMsg: value })), + setAlert: (value: boolean) => set((state) => ({ ...state, alert: value })), + setAlertBtn: (value: Function) => set((state) => ({ ...state, alertBtn: value })), + setAlert2: (value: boolean) => set((state) => ({ ...state, alert2: value })), + setAlert2BtnYes: (value: Function) => set((state) => ({ ...state, alert2BtnYes: value })), + setAlert2BtnNo: (value: Function) => set((state) => ({ ...state, alert2BtnNo: value })), + setSuitableDetailPopup: (value: boolean) => set((state) => ({ ...state, suitableDetailPopup: value })), reset: () => set(initialState), }))