Skip to content

Commit

Permalink
#112 作品の詳細編集機能追加
Browse files Browse the repository at this point in the history
  • Loading branch information
FltSv committed Aug 23, 2024
1 parent f58d04e commit 01ff3c2
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 28 deletions.
15 changes: 14 additions & 1 deletion Hosting/src/Data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ export async function getCreatorData(user: User) {
const fbProducts = data.products ?? [];
creator.products = fbProducts.map(x => ({
id: x.id,
title: x.title ?? '',
detail: x.detail ?? '',
srcImage: x.image,
imageUrl: creatorUrl + x.image,
tmpImageData: '',
Expand Down Expand Up @@ -112,7 +114,12 @@ export async function setCreatorData(user: User, data: Creator) {
);
await setDoc(docRef, {
name: data.name,
products: data.products.map(x => ({ id: x.id, image: x.srcImage })),
products: data.products.map(x => ({
id: x.id,
title: x.title,
detail: x.detail,
image: x.srcImage,
})),
exhibits: data.exhibits.map(x => ({
id: x.id,
title: x.title,
Expand Down Expand Up @@ -317,6 +324,12 @@ export interface Creator {
/** 発表作品 */
export interface Product extends ImageStatus {
id: string;

/** 作品名 */
title: string;

/** 作品説明、他 */
detail: string;
}

/** 展示 */
Expand Down
174 changes: 147 additions & 27 deletions Hosting/src/components/pages/Mypage.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { useEffect, useState } from 'react';
import { Dispatch, SetStateAction, useEffect, useState } from 'react';
import { useForm, SubmitHandler, Controller } from 'react-hook-form';
import { Button as MuiJoyButton, IconButton, Card, Input } from '@mui/joy';
import {
Button as MuiJoyButton,
IconButton,
Card,
Input,
Textarea,
} from '@mui/joy';
import { Autocomplete } from '@mui/material';
import { FaCheck, FaPen, FaPlus, FaTimes } from 'react-icons/fa';
import { useAuthContext } from 'components/AuthContext';
Expand All @@ -24,9 +30,11 @@ export const Mypage = () => {
const { user } = useAuthContext();
const [creator, setCreator] = useState<Creator>();
const [loading, setLoading] = useState(true);
const [visiblePopup, setVisiblePopup] = useState(false);
const [visibleProductPopup, setVisibleProductPopup] = useState(false);
const [visibleExhibitPopup, setVisibleExhibitPopup] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const [editExhibit, setEditExhibit] = useState<Exhibit | undefined>();
const [editExhibit, setEditExhibit] = useState<Exhibit>();
const [editProduct, setEditProduct] = useState<Product>();

useEffect(() => {
// データの取得
Expand Down Expand Up @@ -107,6 +115,8 @@ export const Mypage = () => {
const url = URL.createObjectURL(file);
const product: Product = {
id: getUlid(),
title: '',
detail: '',
tmpImageData: url,
srcImage: '',
imageUrl: '',
Expand Down Expand Up @@ -135,6 +145,10 @@ export const Mypage = () => {
<ProductCell
key={product.id}
data={product}
onEdit={() => {
setEditProduct(product);
setVisibleProductPopup(true);
}}
onDelete={() => {
const newProducts = creator.products.filter(
x => x.id !== product.id,
Expand All @@ -157,7 +171,7 @@ export const Mypage = () => {
startDecorator={<FaPlus />}
onClick={() => {
setEditExhibit(undefined);
setVisiblePopup(true);
setVisibleExhibitPopup(true);
}}>
展示追加
</Button>
Expand All @@ -170,7 +184,7 @@ export const Mypage = () => {
data={exhibit}
onEdit={() => {
setEditExhibit(exhibit);
setVisiblePopup(true);
setVisibleExhibitPopup(true);
}}
onDelete={() => {
const newExhibits = creator.exhibits.filter(
Expand All @@ -193,8 +207,30 @@ export const Mypage = () => {
</SubmitButton>
</form>

{/* <!-- popup window --> */}
<Popup visible={visiblePopup} setVisible={setVisiblePopup}>
{/* 発表作品 */}
{editProduct && (
<ProductPopup
visible={visibleProductPopup}
setVisible={setVisibleProductPopup}
product={editProduct}
onSubmit={newValue => {
if (creator === undefined) {
return;
}

const editIndex = creator.products.indexOf(editProduct);
if (editIndex !== -1) {
creator.products[editIndex] = newValue;
}

setCreator(creator);
setVisibleProductPopup(false);
}}
/>
)}

{/* 展示登録 */}
<Popup visible={visibleExhibitPopup} setVisible={setVisibleExhibitPopup}>
<ExhibitForm
exhibit={editExhibit}
onSubmit={newValue => {
Expand All @@ -214,7 +250,7 @@ export const Mypage = () => {
}

setCreator(creator);
setVisiblePopup(false);
setVisibleExhibitPopup(false);
}}
/>
</Popup>
Expand All @@ -224,32 +260,49 @@ export const Mypage = () => {

interface ProductCellProps {
data: Product;
onEdit: (product: Product) => void;
onDelete: (product: Product) => void;
sortableProps: SortableProps;
}

const ProductCell = (props: ProductCellProps) => {
const { data, onDelete, sortableProps } = props;
const { data, onEdit, onDelete, sortableProps } = props;

return (
<div className="relative min-w-fit">
<img
className="h-28 p-2 md:h-40"
key={data.id}
src={data.tmpImageData || data.imageUrl}
{...sortableProps}
/>
<IconButton
size="sm"
variant="soft"
color="neutral"
sx={{ borderRadius: 9999 }}
className="absolute right-0 top-0"
onClick={() => {
onDelete(data);
}}>
<FaTimes />
</IconButton>
<div className="relative">
<img
className="h-28 p-2 md:h-40"
key={data.id}
src={data.tmpImageData || data.imageUrl}
{...sortableProps}
/>
<p className="absolute bottom-0 w-fit bg-black bg-opacity-50 px-2 text-white">
{data.title}
</p>
</div>
<div className="absolute right-0 top-0 flex flex-col gap-2">
<IconButton
size="sm"
variant="soft"
color="neutral"
sx={{ borderRadius: 9999 }}
onClick={() => {
onEdit(data);
}}>
<FaPen />
</IconButton>
<IconButton
size="sm"
variant="soft"
color="neutral"
sx={{ borderRadius: 9999 }}
onClick={() => {
onDelete(data);
}}>
<FaTimes />
</IconButton>
</div>
</div>
);
};
Expand Down Expand Up @@ -306,6 +359,73 @@ const ExhibitRow = (props: ExhibitRowProps) => {
);
};

interface ProductPopupProps {
visible: boolean;
setVisible: Dispatch<SetStateAction<boolean>>;
product: Product;
onSubmit: (newValue: Product) => void;
}

const ProductPopup = (props: ProductPopupProps) => {
const { visible, setVisible, product, onSubmit } = props;
const { register, handleSubmit, reset } = useForm({
defaultValues: product,
});

useEffect(() => {
reset(product);
}, [product, reset]);

const onValid: SubmitHandler<Product> = data => {
const submitData: Product = {
...product,
title: data.title,
detail: data.detail,
};

onSubmit(submitData);
};

return (
<Popup visible={visible} setVisible={setVisible}>
<form
onSubmit={e => {
e.preventDefault();
void handleSubmit(onValid)(e);
}}>
<h2 className="w-fit">作品情報編集</h2>

<div className="mb-4 mt-2 flex max-w-2xl flex-col gap-4 md:flex-row">
<div className="flex max-w-max basis-1/2 flex-col">
<img
className="w-full max-w-xs"
src={product.tmpImageData || product.imageUrl}
/>
</div>
<div className="flex basis-1/2 flex-col gap-2 md:w-max">
<Textbox label="作品名" {...register('title')} />
<div>
<p>詳細</p>
<Textarea
sx={{ border: 1, borderColor: 'black', marginY: '0.25rem' }}
minRows={3}
{...register('detail')}
/>
</div>
</div>
</div>

<SubmitButton
className="w-fit rounded-md border border-black bg-white text-black"
variant="outlined"
startDecorator={<FaCheck />}>
変更
</SubmitButton>
</form>
</Popup>
);
};

interface ExhibitFormProps {
exhibit?: Exhibit;
onSubmit: (newValue: Exhibit) => void;
Expand Down
2 changes: 2 additions & 0 deletions Hosting/src/firebase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@ export interface Creator {
/** firestore Product */
export interface Product {
id: string;
title?: string;
detail?: string;
image: string;
}

Expand Down

0 comments on commit 01ff3c2

Please sign in to comment.