Skip to content

Commit

Permalink
feat: initalize preview step
Browse files Browse the repository at this point in the history
  • Loading branch information
LinaYahya committed Jul 2, 2024
1 parent 6b37fd1 commit f4a0fe1
Show file tree
Hide file tree
Showing 16 changed files with 603 additions and 25 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
"@uppy/xhr-upload": "^3.6.7",
"i18next": "^23.9.0",
"react": "18.3.1",
"react-beautiful-dnd": "^13.1.1",
"react-dom": "18.3.1",
"react-draggable": "^4.4.6",
"react-i18next": "14.1.2",
Expand Down Expand Up @@ -69,6 +70,7 @@
"@cypress/code-coverage": "3.12.39",
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
"@types/i18n": "0.13.12",
"@types/react-beautiful-dnd": "^13",
"@types/uuid": "9.0.8",
"@typescript-eslint/eslint-plugin": "7.14.1",
"@typescript-eslint/parser": "7.14.1",
Expand Down
10 changes: 10 additions & 0 deletions src/@types/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export type Settings = {
description: string;
labels: Label[];
imageDimension: { width: number; height: number };
};

export enum SettingsKeys {
Expand All @@ -16,3 +17,12 @@ export type Label = {
};

export type Choice = { content: string; id: string };

export type DraggableLabel = {
// x and y are relative to image size
y: string;
x: string;
choices: Choice[];
ind: number;
labelId: string;
};
1 change: 1 addition & 0 deletions src/langs/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,5 @@ export const APP = {
BACK: 'BACK',
REPLACE_IMAGE: 'REPLACE_IMAGE',
ADD: 'ADD',
DRAG_DROP_EXERCISE_TITLE: 'DRAG_DROP_EXERCISE_TITLE',
};
3 changes: 2 additions & 1 deletion src/langs/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@
"NEXT": "Next",
"BACK": "Back",
"REPLACE_IMAGE": "Replace the image",
"ADD": "Add"
"ADD": "Add",
"DRAG_DROP_EXERCISE_TITLE": "Drag and drop these labels into the correct frame of the image"
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { hooks, mutations } from '@/config/queryClient';
import { APP } from '@/langs/constants';

import AddDraggableLabel from './AddDraggableLabel';
import { useImageDimensionsContext } from './imageDimensionContext';

type Props = {
moveToNextStep: () => void;
Expand All @@ -19,6 +20,7 @@ const AddLabelsStep = ({
moveToPrevStep,
}: Props): JSX.Element => {
const { t } = useAppTranslation();
const { imgRef } = useImageDimensionsContext();

const { data: appSettings } = hooks.useAppSettings<Settings>();
const { mutate: patchSetting } = mutations.usePatchAppSetting();
Expand All @@ -33,8 +35,10 @@ const AddLabelsStep = ({
);

const saveData = (): void => {
if (settingsData) {
const data = { ...settingsData.data, labels };
if (settingsData && imgRef?.current) {
const { width, height } = imgRef.current.getBoundingClientRect();
const imageDimension = { width, height };
const data = { ...settingsData.data, labels, imageDimension };
patchSetting({ id: settingsData?.id, data });
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { styled } from '@mui/material';

import { hooks } from '@/config/queryClient';

import { useImageDimensionsContext } from './imageDimensionContext';

const Container = styled('div')(() => ({
display: 'flex',
justifyContent: 'center',
Expand All @@ -21,12 +23,14 @@ const ImageFrame = ({ appSettingId }: Props): JSX.Element | null => {
const { data: dataFile } = hooks.useAppSettingFile({
appSettingId,
});
const { imgRef } = useImageDimensionsContext();

return dataFile ? (
<Container>
<img
src={URL.createObjectURL(dataFile)}
alt="frame"
ref={imgRef}
style={{
maxWidth: '100%',
maxHeight: '100%',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React, { createContext, useContext, useMemo, useRef } from 'react';

const ImageDimensionsContext = createContext<ImageDimensionContextType>({
imgRef: null,
});

type Props = {
children: JSX.Element;
};

type ImageDimensionContextType = {
imgRef: React.MutableRefObject<HTMLImageElement | null> | null;
};
export const ImageDimensionsProvider = ({ children }: Props): JSX.Element => {
const imgRef = useRef<HTMLImageElement | null>(null);
const value: ImageDimensionContextType = useMemo(
() => ({ imgRef }),
[imgRef],
);

return (
<ImageDimensionsContext.Provider value={value}>
{children}
</ImageDimensionsContext.Provider>
);
};

export const useImageDimensionsContext = (): ImageDimensionContextType =>
useContext<ImageDimensionContextType>(ImageDimensionsContext);
13 changes: 0 additions & 13 deletions src/modules/builder/configuration/PreviewStep.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from 'react';
import { TransformComponent, TransformWrapper } from 'react-zoom-pan-pinch';

import { Box } from '@mui/material';

import { DraggableLabel } from '@/@types';

import ImageFrame from './ImageFrame';
import LabelPin, { GroupContainer } from './LabelPin';

type Props = {
isDragging?: boolean;
labels: DraggableLabel[];
imageSettingId: string;
};

const DraggableFrameWithLabels = ({
isDragging,
labels,
imageSettingId,
}: Props): JSX.Element => {
const renderDraggableLabels = (): JSX.Element | JSX.Element[] => {
const Labels = labels.map((label) => (
<GroupContainer key={label.ind} top={label.y} left={label.x}>
<LabelPin label={label} />
</GroupContainer>
));

return Labels;
};

return (
<Box sx={{ position: 'relative' }}>
<TransformWrapper
initialScale={1}
panning={{ disabled: isDragging }}
pinch={{ disabled: isDragging }}
wheel={{ disabled: isDragging }}
zoomAnimation={{ disabled: isDragging }}
alignmentAnimation={{ disabled: isDragging }}
velocityAnimation={{ disabled: isDragging }}
>
<TransformComponent
contentStyle={{
width: '100%',
height: '100%',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<ImageFrame appSettingId={imageSettingId} />
{renderDraggableLabels()}
</TransformComponent>
</TransformWrapper>
</Box>
);
};

export default DraggableFrameWithLabels;
31 changes: 31 additions & 0 deletions src/modules/builder/configuration/PreviewStep/ImageFrame.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { hooks } from '@/config/queryClient';

type Props = {
appSettingId: string;
};

const ImageFrame = ({ appSettingId }: Props): JSX.Element | null => {
const { data: dataFile } = hooks.useAppSettingFile({
appSettingId,
});

return dataFile ? (
<img
src={URL.createObjectURL(dataFile)}
alt="frame"
className="image-lina"
style={{
maxWidth: '100%',
maxHeight: '100%',
objectFit: 'cover',
pointerEvents: 'auto',
cursor: 'cell',
// position: 'absolute',
// top: '0px',
// left: '0px',
}}
/>
) : null;
};

export default ImageFrame;
87 changes: 87 additions & 0 deletions src/modules/builder/configuration/PreviewStep/LabelPin.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react';
import { Draggable, Droppable } from 'react-beautiful-dnd';

import { Box, styled } from '@mui/material';

import { DraggableLabel } from '@/@types';

export const Label = styled('div')<{ isDraggable: boolean }>(
({ theme, isDraggable }) => ({
background: 'red',
color: 'white',
borderRadius: theme.spacing(1),
userSelect: 'none',
padding: theme.spacing(0.5),
...(isDraggable && {
left: 'auto !important',
top: 'auto !important',
}),
}),
);

export const GroupContainer = styled(Box)<{
top: string;
left: string;
}>(({ theme, top, left }) => ({
borderRadius: theme.spacing(1),
background: 'white',
position: 'absolute',
top,
left,
display: 'flex',
gap: theme.spacing(1),
border: '1px solid white',
borderColor: 'black',
minHeight: '4ch',
minWidth: '8ch',
}));

type Props = {
label: DraggableLabel;
draggingOverItem?: boolean;
};

const LabelPin = ({ label }: Props): JSX.Element => (
<Droppable
droppableId={`${label.ind}`}
// isDropDisabled={!draggingOverItem}
>
{(provided) => (
<div
ref={provided.innerRef}
{...provided.droppableProps}
style={{ background: 'green', display: 'flex' }}
>
{label.choices?.map((item, index) => (
<Draggable
key={item?.id}
draggableId={item?.id}
index={index}
// isDragDisabled={!draggingOverItem}
>
{(dragProvided, dragSnapshot) => (
<Label
ref={dragProvided.innerRef}
{...dragProvided.draggableProps}
{...dragProvided.dragHandleProps}
isDraggable={dragSnapshot.isDragging}
>
<Box
display="flex"
sx={{
position: 'relative',
}}
>
{item.content}
</Box>
</Label>
)}
</Draggable>
))}
{provided.placeholder}
</div>
)}
</Droppable>
);

export default LabelPin;
Loading

0 comments on commit f4a0fe1

Please sign in to comment.