Skip to content

Commit

Permalink
Merge branch 'photocard-new-feature' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
Daybreak312 committed Jun 28, 2024
2 parents e2b4f4a + 07e287b commit 8bcc371
Show file tree
Hide file tree
Showing 16 changed files with 328 additions and 57 deletions.
3 changes: 3 additions & 0 deletions public/Check.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/Share.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions public/Zoom.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 4 additions & 2 deletions src/component/body/photocard/PhotoCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,17 @@ export interface PhotoCardProps {

export const PhotoCard = (
props: PhotoCardProps,
setModel: (value: JSX.Element | undefined) => void
setModel: (value: JSX.Element | undefined) => void,
toast: JSX.Element | undefined,
setToast: (value: JSX.Element | undefined) => void
) => {

const isLiked = new AnyRepository<boolean>(false)

return (
<div key={"photo-card" + props.id} className={`flex `}>
<div onClick={() => {
PhotoCardModal(props, setModel, isLiked)
PhotoCardModal(props, setModel, isLiked, toast, setToast)
}}>
<PhotoCardImage width={"220px"} height={"340px"} image={props.image}/>
</div>
Expand Down
7 changes: 6 additions & 1 deletion src/component/body/photocard/PhotoCardComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ export const PhotoCardComponent = () => {
<SkeletonPhotoCards/>
);

const [toast, setToast] =
useState<JSX.Element>()
const [modal, setModal] =
useState<JSX.Element | undefined>()

Expand All @@ -32,7 +34,9 @@ export const PhotoCardComponent = () => {
props,
(value: JSX.Element | undefined) => {
setModal(value)
}
},
toast,
setToast
)
)
}
Expand All @@ -45,6 +49,7 @@ export const PhotoCardComponent = () => {
<>
{component}
{modal && modal}
{toast}
</>
)
}
143 changes: 93 additions & 50 deletions src/component/body/photocard/PhotoCardModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ import {BlurModal} from "../modal/BlurModal";
import {HttpMethod} from "../../../module/request/ServerInfo";
import axios from "axios";
import {AnyRepository} from "../../../module/repository/AnyRepository";
import {DivIconButton} from "../../button/DivIconButton";
import {GotoDivIconButton} from "../../button/GotoDivIconButton";
import {PageName} from "../../../initializer/CurrentPage";
import {CompleteCopyToast} from "../toast/CompleteCopyToast";

export interface PhotoCardModalProps {
id: string
Expand All @@ -20,8 +24,95 @@ export interface PhotoCardModalProps {
export const PhotoCardModal = (
props: PhotoCardProps,
setModel: (value: JSX.Element | undefined) => void,
isLiked: AnyRepository<boolean>
isLiked: AnyRepository<boolean>,
toast: JSX.Element | undefined,
setToast: (value: JSX.Element | undefined) => void
) => {

const PhotoCardModalInfo = (props: PhotoCardModalProps) => {
return (
<div className={"flex flex-col items-center"}>
<p className={"text-text-white font-p-semi-bold text-[36px]"}>{props.name}</p>
<p className={"text-text-subtext2 font-preahvihear text-[24px]"}>
{`${props.groupName}, ${props.memberNickname != null ? (props.memberNickname + " ") : ""}${props.memberName}`}
</p>
<p className={"text-text-subtext3 font-p-light text-[20px]"}>
{props.createdAt}
</p>
</div>
)
}

const PhotoCardModalImages = (props: PhotoCardModalProps) => {
return (
<div className={`flex gap-[30px]`}>
<PhotoCardImage image={props.image} width={"275px"} height={"425px"}/>
<PhotoCardImage image={props.backImage} width={"275px"} height={"425px"}/>
</div>
)
}

const Buttons = (props: PhotoCardModalProps) => {
return (
<div className={"flex flex-row gap-[10px] items-center justify-center"}>
{PhotoCardLikeApi(props)}
<DivIconButton
iconProps={{
iconUri: "/Share.svg",
iconWidth: "40px",
iconHeight: "40px"
}}
gap={"10px"} className={`rounded-[10px] p-[10px] hover:bg-photocard-addicon animated`}
text={"공유하기"} textSize={"32px"}
onClick={() => {
navigator.clipboard.writeText(location.host + `/${PageName.PHOTOCARD}/${props.id}`)
if (toast === undefined) {
setToast(
<CompleteCopyToast toast={toast} setToast={setToast}/>
)
}
}}
/>
<GotoDivIconButton
gotoPath={`/${PageName.PHOTOCARD}/${props.id}`}
iconProps={{
iconUri: "/Zoom.svg",
iconWidth: "40px",
iconHeight: "40px"
}}
gap={"10px"} className={"rounded-[10px] p-[10px] hover:bg-photocard-addicon animated"}
text={"크게보기"} textSize={"32px"}/>
</div>
)
}

const PhotoCardLikeApi = (props: PhotoCardModalProps) => {

return (
<div
className={"flex flex-row gap-[10px] items-center p-[10px] rounded-[10px] hover:bg-photocard-addicon animated"}
onClick={(event) => {
event.stopPropagation()
if (!isLiked.data) {
isLiked.data = true

axios.request({
method: HttpMethod.PATCH,
url: `/sphoto-card/like/${props.id}`
}).catch();

(event.currentTarget.firstChild as HTMLImageElement).src = "/Filled Heart.svg";
(event.currentTarget.lastChild as HTMLPreElement).innerHTML =
(++(props.likeCount)).toString();
}
}}>
<img src={isLiked.data ? "/Filled Heart.svg" : "/Heart.svg"}
width={"40px"} height={"40px"} alt={"heart"}/>
<p className={"text-text-white font-p-regular text-[32px]"}>{props.likeCount}</p>
</div>
)
}

axios.request({
method: HttpMethod.GET,
url: `/photo-cards/${props.id}`
Expand All @@ -35,58 +126,10 @@ export const PhotoCardModal = (
setModel={setModel}>
{PhotoCardModalInfo(props)}
{PhotoCardModalImages(props)}
{PhotoCardLikeApi(props, isLiked)}
{Buttons(props)}
</BlurModal>
)
})

}

const PhotoCardModalInfo = (props: PhotoCardModalProps) => {
return (
<div className={"flex flex-col items-center"}>
<p className={"text-text-white font-p-semi-bold text-[36px]"}>{props.name}</p>
<p className={"text-text-subtext2 font-preahvihear text-[24px]"}>
{`${props.groupName}, ${props.memberNickname != null ? (props.memberNickname + " ") : ""}${props.memberName}`}
</p>
<p className={"text-text-subtext3 font-p-light text-[20px]"}>
{props.createdAt}
</p>
</div>
)
}

const PhotoCardModalImages = (props: PhotoCardModalProps) => {
return (
<div className={`flex gap-[30px]`}>
<PhotoCardImage image={props.image} width={"275px"} height={"425px"}/>
<PhotoCardImage image={props.backImage} width={"275px"} height={"425px"}/>
</div>
)
}

const PhotoCardLikeApi = (props: PhotoCardModalProps, isLiked: AnyRepository<boolean>) => {

return (
<div className={"flex flex-row gap-[10px] p-[10px"}
onClick={(event) => {
event.stopPropagation()
if (!isLiked.data) {
isLiked.data = true

axios.request({
method: HttpMethod.PATCH,
url: `/photo-cards/like/${props.id}`
}).catch();

(event.currentTarget.firstChild as HTMLImageElement).src = "/Filled Heart.svg";
(event.currentTarget.lastChild as HTMLPreElement).innerHTML =
(++(props.likeCount)).toString();
}
}}>
<img src={isLiked.data ? "/Filled Heart.svg" : "/Heart.svg"}
width={"40px"} height={"40px"} alt={"heart"}/>
<p className={"text-text-white font-p-regular text-[32px]"}>{props.likeCount}</p>
</div>
)
}
6 changes: 4 additions & 2 deletions src/component/body/photocard/PhotoCards.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ export interface PhotoCardsProps {

export const PhotoCards = (
props: PhotoCardsProps,
setModel: (value: JSX.Element | undefined) => void
setModel: (value: JSX.Element | undefined) => void,
toast: JSX.Element | undefined,
setToast: (value: JSX.Element | undefined) => void
) => {

if (props.photoCardProps === undefined) {
Expand All @@ -15,6 +17,6 @@ export const PhotoCards = (
}

return <div className={`flex flex-wrap gap-[50px] w-full justify-center items-start content-center p-[100px]`}>
{props.photoCardProps.map((value) => PhotoCard(value, setModel))}
{props.photoCardProps.map((value) => PhotoCard(value, setModel, toast, setToast))}
</div>
}
15 changes: 15 additions & 0 deletions src/component/body/toast/CompleteCopyToast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {Toast} from "./Toast";

export interface CompleteCopyToastProps {
toast: JSX.Element | undefined
setToast: (toast: JSX.Element | undefined) => void
}

export const CompleteCopyToast = (props: CompleteCopyToastProps) => {
return <Toast
currentToast={props.toast}
setToast={props.setToast}>
<img src={"/Check.svg"} width={"40px"} alt={""}/>
<p className={"text-text-white text-[30px] font-p-regular"}>링크가 복사되었습니다!</p>
</Toast>
}
33 changes: 33 additions & 0 deletions src/component/body/toast/Toast.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
export interface ToastProps {
children: JSX.Element[]
className?: string
currentToast: JSX.Element | undefined
setToast: (value: JSX.Element | undefined) => void
}

export const Toast = (props: ToastProps) => {

const animeId = setTimeout(() => {
try {
document.getElementById('toast')!.className += " toast-down-animation"
} catch (e) {
if (e instanceof TypeError) {
// 상관 없음
return
}
console.error(e)
}
}, 4000)
const removeId = setTimeout(() => {
props.setToast(undefined)
}, 5000)


return (
<div
id={`toast`}
className={`fixed bottom-[30px] right-[30px] flex flex-row items-center h-[100px] bg-background-highlight border-[1px] border-solid border-photocard-stroke gap-[10px] px-[30px] py-[10px] rounded-[30px] toast-up-animation ${props.className}`}>
{props.children}
</div>
)
}
4 changes: 3 additions & 1 deletion src/component/button/DivIconButton.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import {MouseEvent} from "react";

export interface IconProps {
readonly iconUri: string,
readonly iconWidth: string,
Expand All @@ -7,7 +9,7 @@ export interface IconProps {
export interface DivIconButtonProps {
readonly iconProps: IconProps,
readonly gap: string,
readonly onClick?: () => void,
readonly onClick?: ((event: React.MouseEvent) => void) | (() => void),
readonly text?: string,
readonly textSize?: string,
readonly className?: string,
Expand Down
24 changes: 24 additions & 0 deletions src/component/button/GotoDivIconButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import {DivIconButton, IconProps} from "./DivIconButton";

export interface GotoDivIconButtonProps {
iconProps: IconProps
gap?: string
text: string
textSize: string
gotoPath: string
className?: string
}

export const GotoDivIconButton = (props: GotoDivIconButtonProps) => {
return (
<a href={props.gotoPath}>
<DivIconButton
iconProps={props.iconProps}
gap={props.gap ? props.gap : "10px"}
text={props.text}
textSize={props.textSize}
className={`p-[10px] ${props.className}`}
/>
</a>
)
}
28 changes: 28 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,34 @@
}
}

.toast-up-animation {
animation: toast-up-animation 0.5s ease-in-out;
}

@keyframes toast-up-animation {
0% {
opacity: 0;
transform: translate3d(0, 100%, 0);
}
to {
opacity: 1;
transform: translate3d(0, 0, 0);
}
}

.toast-down-animation {
animation: toast-down-animation 2s ease-in-out;
}

@keyframes toast-down-animation {
0% {
transform: translate3d(0, 0, 0);
}
to {
transform: translate3d(0, 600%, 0);
}
}

html {
background-color: var(--background-default);
}
Expand Down
3 changes: 3 additions & 0 deletions src/initializer/CurrentPage.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export enum PageName {
PHOTOCARD = "photocard",
POPULAR = "popular",
LATEST = "latest",
GROUP = "group",
Expand Down Expand Up @@ -41,6 +42,8 @@ export const CurrentPageInitializer = () => {
// eslint-disable-next-line no-restricted-globals
const paths = location.href.split('/')

console.log(paths)

paths.forEach((it) => {
if (CurrentPage.isPageName(it)) {
CurrentPage.initialCurrentPage(it as PageName)
Expand Down
Loading

0 comments on commit 8bcc371

Please sign in to comment.