From 3f5e037c991f3d0d567eb5017c8c690570ada4d4 Mon Sep 17 00:00:00 2001 From: hhhello Date: Sat, 18 Jan 2025 21:13:27 +0900 Subject: [PATCH] BaseMusic --- .../template/component/GalleryTemplate.tsx | 12 +- .../template/component/PreviewTemplate.tsx | 2 - src/designsystem/component/checkbox.tsx | 8 +- .../component/DashboardInvitationCell.tsx | 2 +- .../design/option/BaseMusicOption.tsx | 180 ++++++++++++++---- .../design/option/TemplateOption.tsx | 12 +- src/page/templates/component/TemplateCell.tsx | 2 +- src/remote/api/FileApi.ts | 3 +- src/remote/value/Music.ts | 11 ++ 9 files changed, 183 insertions(+), 49 deletions(-) create mode 100644 src/remote/value/Music.ts diff --git a/src/component/template/component/GalleryTemplate.tsx b/src/component/template/component/GalleryTemplate.tsx index 5986cba..0d89c3b 100644 --- a/src/component/template/component/GalleryTemplate.tsx +++ b/src/component/template/component/GalleryTemplate.tsx @@ -89,13 +89,13 @@ function GallerySlide( return ( - + {imgList.map((img, index) => ( ))} @@ -179,12 +179,12 @@ const S = { align-self: stretch; overflow-x: hidden; `, - scroll: styled.div<{ slideStyle: GallerySlideStyle }>` + scroll: styled.div<{ $slideStyle: GallerySlideStyle }>` scroll-snap-type: x mandatory; overflow-x: scroll; overflow-y: hidden; display: flex; - ${({slideStyle}) => slideStyle === 'style1' && css` + ${({$slideStyle}) => $slideStyle === 'style1' && css` gap: 8px; `}; ${hideScrollBar}; @@ -197,10 +197,10 @@ const S = { `, slideImg: styled.img<{ $rootWidth: number, - slideStyle: GallerySlideStyle + $slideStyle: GallerySlideStyle }>` display: flex; - ${({$rootWidth, slideStyle}) => slideStyle === 'style1' ? css` + ${({$rootWidth, $slideStyle}) => $slideStyle === 'style1' ? css` width: ${$rootWidth - 34 * 2}px; &:first-child { diff --git a/src/component/template/component/PreviewTemplate.tsx b/src/component/template/component/PreviewTemplate.tsx index 7c0498a..bb337cb 100644 --- a/src/component/template/component/PreviewTemplate.tsx +++ b/src/component/template/component/PreviewTemplate.tsx @@ -30,9 +30,7 @@ function PreviewTemplate( }: PreviewTemplateProps ) { const dateString = `${weddingSchedule.weddingDate} ${weddingSchedule.weddingTime}`; - console.log(dateString) const date = parse(dateString, 'yyyy-MM-dd HH:mm', new Date()); - console.log(date) const isValidDate = !isNaN(date.getTime()); switch (template.templateName) { diff --git a/src/designsystem/component/checkbox.tsx b/src/designsystem/component/checkbox.tsx index 1bfb1b2..a8ebf5a 100644 --- a/src/designsystem/component/checkbox.tsx +++ b/src/designsystem/component/checkbox.tsx @@ -1,7 +1,7 @@ import React, { CSSProperties, ForwardedRef, - forwardRef, + forwardRef, useEffect, useImperativeHandle, useRef, useState @@ -38,6 +38,10 @@ function Checkbox( const [localChecked, setLocalChecked] = useState(checked); const checkboxRef = useRef(null); + useEffect(() => { + setLocalChecked(checked); + }, [checked]); + useImperativeHandle(ref, () => ({ value: localChecked, focus: () => { @@ -85,7 +89,7 @@ function Checkbox( }} />} - {label && {label}} + {label && onChange?.(!checked)}>{label}} ); } diff --git a/src/page/invitation/dashboard/component/DashboardInvitationCell.tsx b/src/page/invitation/dashboard/component/DashboardInvitationCell.tsx index 9656484..a695967 100644 --- a/src/page/invitation/dashboard/component/DashboardInvitationCell.tsx +++ b/src/page/invitation/dashboard/component/DashboardInvitationCell.tsx @@ -73,7 +73,7 @@ ${baseInfo.groomName}, ${baseInfo.brideName}님의 링크메리 모바일 청첩 - + {weddingInfo.url} diff --git a/src/page/invitation/design/option/BaseMusicOption.tsx b/src/page/invitation/design/option/BaseMusicOption.tsx index 19b8334..5256ec3 100644 --- a/src/page/invitation/design/option/BaseMusicOption.tsx +++ b/src/page/invitation/design/option/BaseMusicOption.tsx @@ -1,4 +1,4 @@ -import React, {useRef, useState} from 'react'; +import React, {ChangeEvent, useEffect, useRef, useState} from 'react'; import styled from "styled-components"; import {Column, Row} from "@designsystem/component/flexLayout"; import HorizontalDivider from "@designsystem/component/horizontalDivider"; @@ -9,6 +9,9 @@ import Icon, {IconType} from "@designsystem/foundation/icon"; import OptionSegmentedButton from "@page/invitation/design/component/OptionSegmentedButton"; import Text from "@designsystem/component/text"; import BaseMusic from "@remote/value/BaseMusic"; +import fileApi from "@remote/api/FileApi"; +import Music, {getMusicName} from "@remote/value/Music"; +import LoadingOverlay from "@src/component/LoadingOverlay"; type SelectMode = 'select' | 'direct'; const selectModeRecord: Record = { @@ -29,46 +32,148 @@ function BaseMusicOption( onChange }: BaseMusicOptionProps ) { - const audioRef = useRef(null); - const [selectedAudio, setSelectedAudio] = useState(); + const audioRef = useRef(null); + const [selectedPlayingMusicUrl, setSelectedPlayingMusicUrl] = useState(); const [selectedSelectMode, setSelectedSelectMode] = useState(0); + const [musics, setMusics] = useState(); + const imageFieldRef = useRef(null); + const [isFetching, setIsFetching] = useState(false); + const currentSelectMode = baseMusic.musicUrl === '' ? 0 : musics?.map(i => i.url).includes(baseMusic.musicUrl) ? 0 : 1; + + const uploadAudio = async (event: ChangeEvent) => { + const files = event.target.files; + if (!files) return; + + const file = files[0]; + if (!file) return; + + setIsFetching(true); + const {data} = await fileApi.upload(file); + + onChange({...baseMusic, musicUrl: data.url}); + setIsFetching(false); + }; + + useEffect(() => { + (async () => { + const {data} = await fileApi.getMusics(); + setMusics(data); + })(); + }, []); + + const onClickPlayMusic = async (music: Music) => { + const audio = audioRef.current; + if (!audio) return; + + if (!selectedPlayingMusicUrl) { + setSelectedPlayingMusicUrl(music.url); + audio.src = music.url; + await audio.play(); + return; + } + + if (music.url === selectedPlayingMusicUrl) { + setSelectedPlayingMusicUrl(undefined); + audio.src = ''; + audio.pause(); + } else { + setSelectedPlayingMusicUrl(music.url); + audio.src = music.url; + await audio.play(); + } + } + + const onClickPlayCustomMusic = async () => { + const audio = audioRef.current; + if (!audio) return; + + setSelectedPlayingMusicUrl(baseMusic.musicUrl); + audio.src = baseMusic.musicUrl; + await audio.play(); + } const selectModeContent = () => { switch (selectModes[selectedSelectMode]) { case 'select': - return - - case 'direct': - return - - - 음원 파일 추가 - 최대 4.5MB MP3 파일만 가능 + return ( + + {musics && ( + musics.map((music, index) => ( + + onChange({...baseMusic, musicUrl: music.url})} + /> + + await onClickPlayMusic(music)} + /> + + + )) + )} - ; + ); + case 'direct': + return ( + + {currentSelectMode === 0 ? ( + <> + + + 음원 파일 추가 + 최대 20MB MP3 파일만 가능 + + + + ) : ( + + 배경음악 선택됨 + + { + event.preventDefault(); + onChange({...baseMusic, musicUrl: ''}); + audioRef.current?.pause(); + setSelectedPlayingMusicUrl(undefined); + }} + /> + + )} + {isFetching && } + + ); } }; return ( +