Skip to content

Commit

Permalink
refactor : 초대장 변경 시 위치이동, 크기조절
Browse files Browse the repository at this point in the history
  • Loading branch information
kangjuhyup committed Jan 8, 2025
1 parent e0a48bd commit 496848c
Show file tree
Hide file tree
Showing 6 changed files with 191 additions and 29 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ dist
db
.vscode
out
.vite_cache
.vite_cache
.codegpt
7 changes: 7 additions & 0 deletions packages/page/src/api/dto/letter.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ export interface MetaDetail extends MetaDefault {
angle?: string;
}

export interface MetaText extends MetaDefault {
font: string;
}

export interface PrepareRequest {
thumbnailMeta: MetaDefault;

Expand All @@ -20,13 +24,16 @@ export interface PrepareRequest {
backgroundMeta: MetaDefault;

componentMetas: MetaDetail[];

textMetas: MetaText[];
}

export interface PrepareResponse {
thumbnailUrl: string;
letterUrl: string;
backgroundUrl: string;
componentUrls: string[];
textUrls: string[];
expires: number;
sessionKey: string;
}
Expand Down
8 changes: 2 additions & 6 deletions packages/page/src/api/image.api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,10 @@ import apiClient from '../common/http.client';
import ApiResponse from '../common/response';
import useErrorStore from '../store/error.store';

interface GetPresignedUrlResponse {}

const useImageApi = () => {
const [presignedUrl, setPresignedUrl] = useState<GetPresignedUrlResponse>();
const [presignedUrl, setPresignedUrl] = useState<string>();
const getPresignedUrl = async (path: string) => {
const response = await apiClient.get<ApiResponse<GetPresignedUrlResponse>>(
`/image/${path}`,
);
const response = await apiClient.get<ApiResponse<string>>(`/image/${path}`);
setPresignedUrl(response.data);
return response.data;
};
Expand Down
169 changes: 148 additions & 21 deletions packages/page/src/components/image/presigned/presigned.image.tsx
Original file line number Diff line number Diff line change
@@ -1,40 +1,167 @@
import useImageApi from '@/api/image.api';
import { Image } from '@mantine/core';
import { useEffect } from 'react';
import { Container, Image, Text } from '@mantine/core';
import useMoveResize from '../move/move.resize.hook';
import { useEffect, useState } from 'react';

interface PresignedImageProps {
path: string;
width?: string;
height?: string;
width?: string | number;
height?: string | number;
position?: 'relative' | 'absolute' | 'fixed';
x?: string;
y?: string;
x?: string | number;
y?: string | number;
movable?: boolean;
onUpdate?: (data: {
size: { width: number; height: number };
position: { x: number; y: number };
}) => void;
}

const PresignedImage = ({
path,
width = '100%',
height = '100%',
position,
x,
y,
position = 'relative',
x = 0,
y = 0,
movable = false,
onUpdate,
}: PresignedImageProps) => {
const { presignedUrl, getPresignedUrl } = useImageApi();
const { size, position: pos, handleMouseDown, init } = useMoveResize();
const [contentType, setContentType] = useState<string>('');
const [textContent, setTextContent] = useState<string>('');

useEffect(() => {
if (path) {
getPresignedUrl(path);
}
const fetchData = async () => {
if (path) {
const url = await getPresignedUrl(path);
if (!url) return;
const response = await fetch(url, {
method: 'GET',
});
const type = response.headers.get('Content-Type') || '';
setContentType(type);
if (type === 'text/plain') {
const text = await response.text();
setTextContent(text);
}
}
};
fetchData();
}, [path]);

const extractNumber = (value: string | number) => {
if (typeof value === 'string') {
const match = value.match(/(\d+)/);
return match ? parseInt(match[0], 10) : 0;
}
return value;
};

const initialX = extractNumber(x);
const initialY = extractNumber(y);

useEffect(() => {
if (movable) {
const initialWidth = typeof width === 'string' ? 200 : (width as number);
const initialHeight =
typeof height === 'string' ? 200 : (height as number);
const initialX = extractNumber(x);
const initialY = extractNumber(y);
init(
{ width: initialWidth, height: initialHeight },
{ x: initialX, y: initialY },
);
}
}, [movable]);

useEffect(() => {
if (movable && onUpdate) {
onUpdate({ size, position: pos });
}
}, [size, pos]);

const renderContent = () => {
if (contentType === 'text/plain') {
return (
<Text
style={{
width: '100%',
height: '100%',
overflow: 'hidden',
whiteSpace: 'pre-wrap',
}}
>
{textContent}
</Text>
);
}

return (
<Image
src={presignedUrl}
alt={path}
style={{
width: '100%',
height: '100%',
objectFit: 'fill',
}}
/>
);
};

if (!movable) {
if (contentType === 'text/plain') {
return (
<Text pos={position} top={y} left={x}>
{textContent}
</Text>
);
}

return (
<Image
fit={'fill'}
w={width}
h={height}
src={presignedUrl}
pos={position}
top={y}
left={x}
/>
);
}

return (
<Image
fit={'fill'}
w={width}
h={height}
src={presignedUrl}
pos={position}
top={y}
left={x}
></Image>
<Container
style={{
position: position,
top: pos.y,
left: pos.x,
width: size.width,
height: size.height,
cursor: 'move',
}}
onTouchStart={handleMouseDown}
onMouseDown={handleMouseDown}
>
{renderContent()}
<div
className="resize-handle"
onTouchStart={handleMouseDown}
onMouseDown={handleMouseDown}
style={{
position: 'absolute',
bottom: 0,
right: 0,
width: 20,
height: 20,
backgroundColor: 'gray',
cursor: 'se-resize',
}}
/>
</Container>
);
};

Expand Down
32 changes: 31 additions & 1 deletion packages/page/src/pages/page/create.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,32 @@ const CreatePage = () => {
'x-amz-meta-height': `${files[idx].size.height}`,
'x-amz-meta-width': `${files[idx].size.width}`,
'x-amz-meta-angle': '0',
'x-amz-meta-z': '0',
'x-amz-meta-z': `${idx}`,
'x-amz-meta-x': `${files[idx].position.x}`,
'x-amz-meta-y': `${files[idx].position.y}`,
},
});
}),
);

await Promise.all(
prepareUrls.textUrls.map(async (textUrl, idx) => {
await fetch(textUrl, {
method: 'PUT',
body: texts[idx].text,
headers: {
'Content-Type': 'text/plain',
'x-amz-meta-session': prepareUrls.sessionKey,
'x-amz-meta-height': `${texts[idx].size.height}`,
'x-amz-meta-width': `${texts[idx].size.width}`,
'x-amz-meta-angle': '0',
'x-amz-meta-z': `${idx}`,
'x-amz-meta-x': `${texts[idx].position.x}`,
'x-amz-meta-y': `${texts[idx].position.y}`,
},
});
}),
);
postAddLetter({
category: 'LT001',
title: '테스트',
Expand Down Expand Up @@ -152,6 +171,17 @@ const CreatePage = () => {
angle: '0',
};
}),
textMetas: textData.map((text, idx) => {
return {
width: text.size.width.toString(),
height: text.size.height.toString(),
font: 'Noto Sans KR',
x: text.position.x.toString(),
y: text.position.y.toString(),
z: idx.toString(),
angle: '0',
};
}),
});
return result;
};
Expand Down
1 change: 1 addition & 0 deletions packages/page/src/pages/page/letter/modify/[id].tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const ModifyLetterPage = () => {
/>
{letterDetail.components?.map((component) => (
<PresignedImage
movable
key={component.path}
path={component.path}
width={`${component.width}px`}
Expand Down

0 comments on commit 496848c

Please sign in to comment.