feat: integrate EdgeProvider for alert management and add Suitable components for roof material compatibility checks
This commit is contained in:
parent
4467c04321
commit
1746c91742
@ -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,6 +23,7 @@ interface RootLayoutProps {
|
||||
export default async function RootLayout({ children, header, footer, floatBtn }: RootLayoutProps): Promise<ReactNode> {
|
||||
return (
|
||||
<ReactQueryProviders>
|
||||
<EdgeProvider>
|
||||
<html lang="en">
|
||||
<body>
|
||||
<div className="wrap">
|
||||
@ -33,6 +35,7 @@ export default async function RootLayout({ children, header, footer, floatBtn }:
|
||||
<PopupController />
|
||||
</body>
|
||||
</html>
|
||||
</EdgeProvider>
|
||||
</ReactQueryProviders>
|
||||
)
|
||||
}
|
||||
|
||||
24
src/app/suitable/layout.tsx
Normal file
24
src/app/suitable/layout.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
import { ReactNode } from 'react'
|
||||
|
||||
interface SuitableLayoutProps {
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export default function layout({ children }: SuitableLayoutProps) {
|
||||
return (
|
||||
<>
|
||||
<div className="container">
|
||||
<div className="sale-contents">
|
||||
<div className="border-frame">
|
||||
<div className="pw-guide">
|
||||
<div className="pw-guide-txt">この適合表は参考資料として使用してください.</div>
|
||||
<div className="pw-guide-txt">詳細やお問い合わせは1:1お問い合わせをご利用ください.</div>
|
||||
<div className="pw-guide-txt">屋根材の選択or屋根材名を直接入力してください.</div>
|
||||
</div>
|
||||
</div>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -1,7 +1,9 @@
|
||||
import Suitable from '@/components/suitable/Suitable'
|
||||
|
||||
export default function page() {
|
||||
return (
|
||||
<>
|
||||
<h1>지붕재 적합성</h1>
|
||||
<Suitable />
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
32
src/components/popup/SuitableDetailPopup.tsx
Normal file
32
src/components/popup/SuitableDetailPopup.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
export default function SuitableDetailPopup() {
|
||||
return (
|
||||
<div className="modal-popup">
|
||||
<div className="modal-dialog">
|
||||
<div className="modal-content">
|
||||
<div className="modal-header">
|
||||
<div className="modal-header-inner">
|
||||
<div className="modal-name-wrap">
|
||||
<div className="modal-img">
|
||||
<img src="/assets/images/layout/modal_header_icon03.svg" alt="" />
|
||||
</div>
|
||||
<div className="modal-name">屋根材適合性詳細 </div>
|
||||
</div>
|
||||
<button className="modal-close"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="modal-body">
|
||||
<div className={`compliance-check-bx act`}>
|
||||
<div className="check-name-wrap">
|
||||
<div className="check-name">アースティ40</div>
|
||||
<div className="check-name-btn">
|
||||
<button className="bx-btn"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="compliance-check-pop-contents"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
87
src/components/suitable/Suitable.tsx
Normal file
87
src/components/suitable/Suitable.tsx
Normal file
@ -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 (
|
||||
<div className="border-frame">
|
||||
<div className="sale-form-bx">
|
||||
<select className="select-form" name="" id="">
|
||||
<option value="">屋根材を選択してください.</option>
|
||||
<option value="">屋根材を選択してください.</option>
|
||||
<option value="">屋根材を選択してください.</option>
|
||||
<option value="">屋根材を選択してください.</option>
|
||||
<option value="">屋根材を選択してください.</option>
|
||||
</select>
|
||||
</div>
|
||||
<div className="sale-form-bx">
|
||||
<div className="search-input">
|
||||
<input type="text" className="search-frame" placeholder="屋根材 製品名を入力してください." />
|
||||
<button className="search-icon"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="compliance-check-wrap">
|
||||
<div className={`compliance-check-bx ${reference ? 'act' : ''}`}>
|
||||
<div className="check-name-wrap">
|
||||
<div className="check-name">凡例</div>
|
||||
<div className="check-name-btn">
|
||||
<button className="bx-btn" onClick={() => setReference(!reference)}></button>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="reference-list">
|
||||
<li className="reference-item">
|
||||
<div className="reference-item-bx">
|
||||
<i className="compliance-icon check"></i>設置可能
|
||||
</div>
|
||||
</li>
|
||||
<li className="reference-item">
|
||||
<div className="reference-item-bx">
|
||||
<i className="compliance-icon x"></i>設置可能
|
||||
</div>
|
||||
</li>
|
||||
<li className="reference-item">
|
||||
<div className="reference-item-bx">
|
||||
<i className="compliance-icon quest"></i>設置可能
|
||||
</div>
|
||||
</li>
|
||||
<li className="reference-item">
|
||||
<div className="reference-item-bx">
|
||||
<i className="compliance-icon tip"></i>設置可能
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
{/* checkData */}
|
||||
{/* 데이터 없을경우 버튼 영역 안보여야함 */}
|
||||
<SuitableCheckData />
|
||||
<SuitableCheckData />
|
||||
<SuitableCheckData />
|
||||
<SuitableCheckData />
|
||||
</div>
|
||||
{/* 데이터 없을경우 버튼 영역 안보여야함 */}
|
||||
<div className="btn-flex-wrap com">
|
||||
<div className="btn-bx">
|
||||
<button className="btn-frame n-blue icon">
|
||||
全選択<i className="btn-arr"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div className="btn-bx">
|
||||
<button className="btn-frame red icon">
|
||||
詳細を見る<i className="btn-arr"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div className="btn-bx">
|
||||
<button className="btn-frame n-blue icon">
|
||||
選択ダウンロード<i className="btn-arr"></i>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
{/* 검색기록 없을떄 위에 두 영역 안보이고 이 부분만 보여야 함*/}
|
||||
{/* <SuitableNoData /> */}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
68
src/components/suitable/SuitableCheckData.tsx
Normal file
68
src/components/suitable/SuitableCheckData.tsx
Normal file
@ -0,0 +1,68 @@
|
||||
'use client'
|
||||
|
||||
export default function SuitableCheckData() {
|
||||
return (
|
||||
<>
|
||||
<div className={`compliance-check-bx act`}>
|
||||
<div className="check-name-wrap">
|
||||
<div className="check-form-box com-tit">
|
||||
<input type="checkbox" id="ch01" />
|
||||
<label htmlFor="ch01">アースティ40</label>
|
||||
</div>
|
||||
<div className="check-name-btn">
|
||||
<button className="bx-btn"></button>
|
||||
</div>
|
||||
</div>
|
||||
<ul className="reference-list check">
|
||||
<li className="reference-item">
|
||||
<div className="check-item-wrap">
|
||||
<div className="check-form-box com-txt">
|
||||
<input type="checkbox" id="ch02" />
|
||||
<label htmlFor="ch02">屋根技研 支持瓦</label>
|
||||
</div>
|
||||
<div className="compliance-icon-wrap">
|
||||
<i className="compliance-icon check"></i>
|
||||
<i className="compliance-icon x"></i>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li className="reference-item">
|
||||
<div className="check-item-wrap">
|
||||
<div className="check-form-box com-txt">
|
||||
<input type="checkbox" id="ch03" />
|
||||
<label htmlFor="ch03">屋根技研 支持金具</label>
|
||||
</div>
|
||||
<div className="compliance-icon-wrap">
|
||||
<i className="compliance-icon x"></i>
|
||||
<i className="compliance-icon tip"></i>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li className="reference-item">
|
||||
<div className="check-item-wrap">
|
||||
<div className="check-form-box com-txt">
|
||||
<input type="checkbox" id="ch04" />
|
||||
<label htmlFor="ch04">屋根技研YGアンカー</label>
|
||||
</div>
|
||||
<div className="compliance-icon-wrap">
|
||||
<i className="compliance-icon tip"></i>
|
||||
<i className="compliance-icon quest"></i>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li className="reference-item">
|
||||
<div className="check-item-wrap">
|
||||
<div className="check-form-box com-txt">
|
||||
<input type="checkbox" id="ch05" />
|
||||
<label htmlFor="ch05">ダイドハント支持瓦Ⅱ</label>
|
||||
</div>
|
||||
<div className="compliance-icon-wrap">
|
||||
<i className="compliance-icon check"></i>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
15
src/components/suitable/SuitableNoData.tsx
Normal file
15
src/components/suitable/SuitableNoData.tsx
Normal file
@ -0,0 +1,15 @@
|
||||
export default function SuitableNoData() {
|
||||
return (
|
||||
<>
|
||||
<div className="compliace-nosearch">
|
||||
<span className="mb10">検索結果はありません。</span>
|
||||
<span className="mb10">屋根材適合性表にない製品の情報を入力してください。 今後返信いたします。</span>
|
||||
<span>
|
||||
<button className="btn-frame n-blue icon">
|
||||
お問い合わせ登録<i className="btn-arr"></i>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -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() {
|
||||
<div className="head-block-tit">屋根材の照会</div>
|
||||
<div className="head-block-text">ご使用の屋根材の適合性をご確認いただけます</div>
|
||||
<div className="head-block-link-wrap">
|
||||
<button className="head-block-link">
|
||||
<button className="head-block-link" onClick={() => alert('test')}>
|
||||
照会まさに移動<i className="block-arr"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@ -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 && <MemberInfomationPopup />}
|
||||
{popupController.zipCodePopup && <ZipCodePopup />}
|
||||
{popupController.alert && <Alert />}
|
||||
{popupController.alert2 && <DoubleBtnAlert />}
|
||||
{popupController.suitableDetailPopup && <SuitableDetailPopup />}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
24
src/components/ui/common/Alert.tsx
Normal file
24
src/components/ui/common/Alert.tsx
Normal file
@ -0,0 +1,24 @@
|
||||
'use client'
|
||||
|
||||
import { usePopupController } from '@/store/popupController'
|
||||
|
||||
export default function Alert() {
|
||||
const { alertMsg, alertBtn } = usePopupController()
|
||||
|
||||
return (
|
||||
<div className="modal-popup alert">
|
||||
<div className="modal-dialog">
|
||||
<div className="modal-content">
|
||||
<div className="alert-tit">{alertMsg}</div>
|
||||
<div className="alert-btn-wrap">
|
||||
<div className="alert-btn-bx">
|
||||
<button className="btn-frame red min" onClick={() => alertBtn()}>
|
||||
確認
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
21
src/components/ui/common/DoubleBtnAlert.tsx
Normal file
21
src/components/ui/common/DoubleBtnAlert.tsx
Normal file
@ -0,0 +1,21 @@
|
||||
import React from 'react'
|
||||
|
||||
export default function DoubleBtnAlert() {
|
||||
return (
|
||||
<div className="modal-popup alert">
|
||||
<div className="modal-dialog">
|
||||
<div className="modal-content">
|
||||
<div className="alert-tit">本当に削除しますか?</div>
|
||||
<div className="alert-btn-wrap">
|
||||
<div className="alert-btn-bx">
|
||||
<button className="btn-frame red min">確認</button>
|
||||
</div>
|
||||
<div className="alert-btn-bx">
|
||||
<button className="btn-frame n-blue min">キャンセル</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
64
src/providers/EdgeProvider.tsx
Normal file
64
src/providers/EdgeProvider.tsx
Normal file
@ -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}</>
|
||||
}
|
||||
@ -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<PoupControllerState>((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),
|
||||
}))
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user