Skip to content

Commit

Permalink
Merge pull request #130 from depromeet/feature/archive-issue-fix
Browse files Browse the repository at this point in the history
[Archive] 마블 삭제기능 이슈 해결
  • Loading branch information
Jungjjeong authored Jan 23, 2024
2 parents b506b91 + 1db725c commit ecd82a6
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 165 deletions.
90 changes: 83 additions & 7 deletions src/app/archive/index.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { Body, Composite, Engine } from "matter-js";
import { useEffect, useState } from "react";
import { useLocation } from "react-router-dom";

Expand All @@ -11,6 +12,7 @@ import { ConfirmDialog } from "@/components/common/confirm/confirm-dialog";
import { useApiMarbleCard } from "@/hooks/api/archive/useApiMarbleCard";
import { useApiMarbleList } from "@/hooks/api/archive/useApiMarbleList";
import { TArchiveView, TMarble, TRouteState } from "@/types/archive";
import { createMarbleObject } from "@/utils/createMarbleObject";

export const Archive = () => {
const { state } = useLocation() as TRouteState;
Expand All @@ -30,24 +32,85 @@ export const Archive = () => {
const [isViewedIdList, setIsViewedIdList] = useState<number[]>([]);
const [selectedMarbleId, setSelectedMarbleId] = useState<number>(-1);

// NOTE: Marble Canvas state
const [engine, setEngine] = useState<Matter.Engine>();
const [marbleBodyList, setMarbleBodyList] = useState<Body[]>([]);

// NOTE: Canvas, Grid View value
const [view, setView] = useState<TArchiveView>("preview-card");

// NOTE: Marble detail Open state
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);

useEffect(() => {
const createdEngine = Engine.create({
timing: {
timeScale: 0.8,
},
});
setEngine(createdEngine);
}, []);

useEffect(() => {
if (!marbleData?.pages.length) return;

setMarbleList(marbleData?.pages.flatMap((page) => page.content));
}, [marbleData]);

useEffect(() => {
if (!marbleList.length || !!marbleBodyList.length) return;

const marbles = updateMarbleBodyList(marbleList);
setMarbleBodyList(marbles);
}, [marbleList]);

useEffect(() => {
onChangeModalState(selectedMarbleId !== -1);
}, [selectedMarbleId]);

// NOTE: [DElETE] Delete marble on Canvas
const onDeleteMarbleBody = (deleteId: number) => {
if (!engine) return;

const deleteMarble = engine.world.bodies.find(
({ id, label }) => id === deleteId && label === "marble",
);
if (!deleteMarble) return;
Composite.remove(engine.world, deleteMarble);
};

// NOTE: [MODAL CLOSE] Add marble on Canvas
const onCloseModal = (lastMarbleId: number) => {
setSelectedMarbleId(-1);

if (view !== "marble-canvas" || !engine) return;

const lastSelectedMarble = engine.world.bodies.find(
({ id, label }) => id === lastMarbleId && label === "marble",
);
if (!lastSelectedMarble) return;

Composite.remove(engine.world, lastSelectedMarble);
Composite.add(
engine.world,
createMarbleObject({
id: lastSelectedMarble.id,
textContent: lastSelectedMarble.render.text?.content || "",
isViewed: true,
}),
);
};

// NOTE: [MODAL OPEN] Set selectedMarbleId (set Modal initial index)
const onOpenModal = (id: number) => {
setSelectedMarbleId(id);
};

const onChangeView = (view: TArchiveView) => {
setView(view);

const marbles = updateMarbleBodyList(marbleList);
setMarbleBodyList(marbles);
};

const onChangeModalState = (isOpen: boolean) => {
Expand All @@ -72,7 +135,20 @@ export const Archive = () => {
setIsViewedIdList(updatedIsViewedIdxList);
};

// TODO: Marble 스와이프 후 삭제 시, 삭제된 구슬이 삭제되지 않는 이슈 (모달 진입한 구슬이 삭제)
const updateMarbleBodyList = (marbleList: TMarble[]) => {
return marbleList.map((marbleData) => {
const { commentId, nickname } = marbleData;
const isViewed =
isViewedIdList.findIndex((marbleId) => marbleId === commentId) !== -1;

return createMarbleObject({
id: commentId,
textContent: nickname,
isViewed,
});
});
};

if (!marbleList.length) return null;
return (
<ConfirmDialog>
Expand All @@ -81,8 +157,9 @@ export const Archive = () => {
isOpen={isModalOpen}
selectedMarbleId={selectedMarbleId}
marbleList={marbleList}
onCloseModal={onCloseModal}
onDeleteMarbleBody={onDeleteMarbleBody}
onUpdateMarbleList={onUpdateMarbleList}
onChangeOpenState={onChangeModalState}
onUpdateViewIdxList={onUpdateViewIdxList}
/>
)}
Expand All @@ -96,14 +173,13 @@ export const Archive = () => {
onChangeView={onChangeView}
/>
)}
{view === "marble-canvas" && (
{view === "marble-canvas" && engine && (
<MarbleCanvas
marbleList={marbleList}
selectedMarbleId={selectedMarbleId}
engine={engine}
marbleBodyList={marbleBodyList}
isViewedIdList={isViewedIdList}
isModalOpen={isModalOpen}
onOpenModal={onOpenModal}
onChangeView={onChangeView}
onChangeSelectedMarbleId={onChangeSelectedMarbleId}
/>
)}
{view === "marble-grid" && (
Expand Down
130 changes: 36 additions & 94 deletions src/app/archive/marble-canvas.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,18 @@
/* eslint-disable @typescript-eslint/unbound-method */
// eslint-disable-next-line import/default
import Matter, { IEvent } from "matter-js";
import {
Body,
Engine,
IEvent,
World,
Bodies,
Events,
Mouse,
MouseConstraint,
Runner,
Query,
Composite,
} from "matter-js";
import { useEffect, useRef, useState } from "react";

import Bars from "@/assets/icons/bars.svg";
Expand All @@ -12,80 +24,39 @@ import { Appbar } from "@/components/common/appbar";
import { Header } from "@/components/common/header";
import { ASSET_WIDTH, WIDTH } from "@/constants/archive";
import Render from "@/lib/RenderExtension";
import { TArchiveView, TMarble } from "@/types/archive";
import { createMarbleObject } from "@/utils/createMarbleObject";
import { TArchiveView } from "@/types/archive";
import { setWaitTime } from "@/utils/setWaitTime";

type Props = {
marbleList: TMarble[];
selectedMarbleId: number;
engine: Engine;
marbleBodyList: Body[];
isViewedIdList: number[];
isModalOpen: boolean;
onOpenModal: (id: number) => void;
onChangeView: (view: TArchiveView) => void;
onChangeSelectedMarbleId: (id: number) => void;
};

export const MarbleCanvas = ({
marbleList,
selectedMarbleId,
engine,
marbleBodyList,
isViewedIdList,
isModalOpen,
onOpenModal,
onChangeView,
onChangeSelectedMarbleId,
}: Props) => {
const {
World,
Engine,
Bodies,
Events,
Mouse,
MouseConstraint,
Runner,
Body,
Query,
Composite,
} = Matter;

const [engine, setEngine] = useState<Matter.Engine>();
const [marbleBodyList, setMarbleBodyList] = useState<Matter.Body[]>([]);
const [canvasHeight, setCanvasHeight] = useState<number>(0);

const canvasRef = useRef<HTMLCanvasElement>(null);

useEffect(() => {
const createdEngine = Engine.create({
timing: {
timeScale: 0.8,
},
});
setEngine(createdEngine);
}, []);

// NOTE ===== Create Marble Body Object
useEffect(() => {
if (!marbleList.length) return;

const marbles = marbleList.map((marbleData) => {
const { commentId, nickname } = marbleData;
const isViewed =
isViewedIdList.findIndex((marbleId) => marbleId === commentId) !== -1;
if (!marbleBodyList.length) return;

return createMarbleObject({
id: commentId,
textContent: nickname,
isViewed,
});
});

setCanvasHeight(getCanvasHeight(marbleList.length, WIDTH));
setMarbleBodyList(marbles);
}, [marbleList]);
setCanvasHeight(getCanvasHeight(marbleBodyList.length, WIDTH));
}, [marbleBodyList]);

// NOTE ===== Canvas Setting + Rendering Marble Object
useEffect(() => {
if (!engine || !marbleBodyList.length || !canvasHeight) return;

const render = Render.create({
const canvasRender = Render.create({
engine,
canvas: canvasRef.current!,
options: {
Expand Down Expand Up @@ -159,7 +130,7 @@ export const MarbleCanvas = ({

const selectedBody = bodiesUnderMouse[0];
if (selectedBody && selectedBody.label === "marble") {
onChangeSelectedMarbleId(selectedBody.id);
onOpenModal(selectedBody.id);
}
};

Expand All @@ -181,7 +152,7 @@ export const MarbleCanvas = ({

const selectedBody = mouseConstraint.body;
if (selectedBody && selectedBody.label === "marble") {
onChangeSelectedMarbleId(selectedBody.id);
onOpenModal(selectedBody.id);
}
};

Expand All @@ -190,7 +161,7 @@ export const MarbleCanvas = ({
// 에러 발생으로 임시 수정
const top = Bodies.rectangle(
WIDTH / 2,
-300,
-400,
WIDTH + 60,
ASSET_WIDTH.wall,
{
Expand All @@ -202,7 +173,7 @@ export const MarbleCanvas = ({
);
const floor = Bodies.rectangle(
WIDTH / 2,
canvasHeight + ASSET_WIDTH.wall - 30,
canvasHeight + ASSET_WIDTH.wall - 70,
WIDTH + 60,
ASSET_WIDTH.wall,
{
Expand All @@ -213,7 +184,7 @@ export const MarbleCanvas = ({
},
);
const right = Bodies.rectangle(
WIDTH + 20,
WIDTH + 35,
canvasHeight / 2 - 300,
ASSET_WIDTH.wall,
canvasHeight * 2,
Expand All @@ -225,7 +196,7 @@ export const MarbleCanvas = ({
},
);
const left = Bodies.rectangle(
-20,
-35,
canvasHeight / 2 - 300,
ASSET_WIDTH.wall,
canvasHeight * 2,
Expand All @@ -239,7 +210,7 @@ export const MarbleCanvas = ({
Composite.add(world, [top, floor, right, left]);
};

const mouse = Mouse.create(render.canvas);
const mouse = Mouse.create(canvasRender.canvas);
const mouseConstraint = MouseConstraint.create(engine, {
mouse,
constraint: {
Expand Down Expand Up @@ -268,55 +239,26 @@ export const MarbleCanvas = ({
setupWallsObject();
setupMouseConstraint();

Render.run(render);
Render.run(canvasRender);

for (const marble of marbleBodyList) {
await renderMarbleObject(marble);
}
};

const runner = Runner.run(engine);
const canvasRunner = Runner.run(engine);
void renderEvent();

// NOTE: Initialize of Canvas
return () => {
removeCustomEvent();

Runner.stop(runner);
Render.stop(render);
Runner.stop(canvasRunner);
Render.stop(canvasRender);
World.clear(world, false);
Engine.clear(engine);
};
}, [marbleBodyList, engine]);

// NOTE ===== Modal openState에 따라 selectedMarble hide / render
useEffect(() => {
if (!engine || selectedMarbleId === -1) return;

const selectedMarble = engine.world.bodies.find(
({ id, label }) => id === selectedMarbleId && label === "marble",
);
if (!selectedMarble) return;

if (isModalOpen) {
selectedMarble.render.opacity = 0;
Body.setStatic(selectedMarble, true);
Body.setPosition(selectedMarble, { x: WIDTH / 2, y: 50 });
return;
}

Composite.remove(engine.world, selectedMarble);
Composite.add(
engine.world,
createMarbleObject({
id: selectedMarble.id,
textContent: selectedMarble.render.text?.content || "",
isViewed: true,
}),
);

onChangeSelectedMarbleId(-1);
}, [engine, isModalOpen]);
}, [marbleBodyList, engine, canvasHeight]);

// NOTE ===== isViewedList 업데이트에 따라 marble 색상 변경
useEffect(() => {
Expand Down
Loading

0 comments on commit ecd82a6

Please sign in to comment.