Skip to content
This repository has been archived by the owner on Apr 25, 2023. It is now read-only.

feat: add delete assets confirm modal and fix bugs #25

Merged
merged 8 commits into from
Jul 8, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export default ({
initialAsset,
selectAsset,
selectedAssets,
onRemove,
}: {
assets?: Asset[];
isMultipleSelectable?: boolean;
Expand All @@ -30,6 +31,7 @@ export default ({
initialAsset?: Asset;
selectAsset?: (assets: Asset[]) => void;
selectedAssets?: Asset[];
onRemove?: (assetIds: string[]) => void;
}) => {
const [layoutType, setLayoutType] = useState<LayoutTypes>("medium");
const [currentSaved, setCurrentSaved] = useState(initialAsset);
Expand All @@ -40,6 +42,16 @@ export default ({

const [filteredAssets, setAssets] = useState(assets);

const [deleteModalVisible, setDeleteModalVisible] = useState(false);

const handleRemove = useCallback(() => {
if (selectedAssets?.length) {
onRemove?.(selectedAssets.map(a => a.id));
selectAsset?.([]);
setDeleteModalVisible(false);
}
}, [onRemove, selectAsset, selectedAssets]);

const iconChoice =
filterSelected === "name"
? reverse
Expand Down Expand Up @@ -129,5 +141,8 @@ export default ({
handleUploadToAsset,
handleReverse,
handleSearch,
deleteModalVisible,
setDeleteModalVisible,
handleRemove,
};
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useCallback } from "react";
import React from "react";
import { useIntl } from "react-intl";

import Button from "@reearth/components/atoms/Button";
Expand All @@ -13,6 +13,7 @@ import { styled } from "@reearth/theme";
import AssetCard from "../AssetCard";
import AssetListItem from "../AssetListItem";
import AssetSelect from "../AssetSelect";
import AssetDeleteModal from "@reearth/components/molecules/Settings/Workspace/Asset/AssetDeleteModal";

import useHooks, { Asset as AssetType, LayoutTypes, FilterTypes } from "./hooks";

Expand Down Expand Up @@ -58,6 +59,9 @@ const AssetContainer: React.FC<Props> = ({
handleUploadToAsset,
handleReverse,
handleSearch,
deleteModalVisible,
setDeleteModalVisible,
handleRemove,
} = useHooks({
assets,
isMultipleSelectable,
Expand All @@ -66,6 +70,7 @@ const AssetContainer: React.FC<Props> = ({
initialAsset,
selectAsset,
selectedAssets,
onRemove,
});

const filterOptions: { key: FilterTypes; label: string }[] = [
Expand All @@ -74,13 +79,6 @@ const AssetContainer: React.FC<Props> = ({
{ key: "name", label: intl.formatMessage({ defaultMessage: "Alphabetical" }) },
];

const handleRemove = useCallback(() => {
if (selectedAssets?.length) {
onRemove?.(selectedAssets.map(a => a.id));
selectAsset?.([]);
}
}, [onRemove, selectAsset, selectedAssets]);

return (
<Wrapper>
<Flex justify={onRemove ? "flex-end" : "center"}>
Expand All @@ -103,7 +101,8 @@ const AssetContainer: React.FC<Props> = ({
icon="bin"
type="button"
buttonType="secondary"
onClick={handleRemove}
disabled={selectedAssets?.length ? false : true}
onClick={() => setDeleteModalVisible(true)}
/>
)}
</Flex>
Expand Down Expand Up @@ -179,6 +178,11 @@ const AssetContainer: React.FC<Props> = ({
)}
<Divider margin="0" />
</AssetWrapper>
<AssetDeleteModal
isVisible={deleteModalVisible}
onClose={() => setDeleteModalVisible(false)}
handleRemove={handleRemove}
/>
</Wrapper>
);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from "react";
import { useIntl } from "react-intl";

import Text from "@reearth/components/atoms/Text";
import Modal from "@reearth/components/atoms/Modal";
import Divider from "@reearth/components/atoms/Divider";
import Button from "@reearth/components/atoms/Button";

import { styled } from "@reearth/theme";
import { metricsSizes } from "@reearth/theme/metrics";

// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface Props {
isVisible: boolean;
onClose?: () => void;
handleRemove?: () => void;
}

const AssetDeleteModal: React.FC<Props> = ({ isVisible, onClose, handleRemove }) => {
const intl = useIntl();
return (
<Modal
title="Delete assets"
isVisible={isVisible}
size="sm"
onClose={onClose}
button1={
<Button
text={intl.formatMessage({ defaultMessage: "Delete" })}
buttonType="danger"
onClick={handleRemove}
/>
}
button2={
<Button
text={intl.formatMessage({ defaultMessage: "Cancel" })}
buttonType="secondary"
onClick={onClose}
/>
}>
<Divider margin="0" />
<Message size="m">
{intl.formatMessage({
defaultMessage:
"You are about to delete assets from the workspace. Any place which use this asset will cause a error. And this is an action that cannot be undone.",
})}
</Message>
<Message size="m">
{intl.formatMessage({
defaultMessage: "Are you sure you would like to delete these assets?",
})}
</Message>
</Modal>
);
};

const Message = styled(Text)`
margin-top: ${`${metricsSizes["2xl"]}px`};
`;
export default AssetDeleteModal;
4 changes: 3 additions & 1 deletion src/components/organisms/Dashboard/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,9 @@ export default (teamId?: string) => {
.filter((project): project is Project => !!project);
}, [team?.projects.nodes]);

const [createNewProject] = useCreateProjectMutation();
const [createNewProject] = useCreateProjectMutation({
refetchQueries: ["Project"],
});
const [createScene] = useCreateSceneMutation();
const createProject = useCallback(
async (data: { name: string; description: string; imageUrl: string | null }) => {
Expand Down
36 changes: 29 additions & 7 deletions src/components/organisms/Settings/ProjectList/hooks.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useState, useCallback, useEffect } from "react";
import { useIntl } from "react-intl";
import { useNavigate } from "@reach/router";

import {
Expand All @@ -8,6 +9,7 @@ import {
useCreateSceneMutation,
Visualizer,
useAssetsQuery,
useCreateAssetMutation,
} from "@reearth/gql";
import { useLocalState } from "@reearth/state";
import { Project } from "@reearth/components/molecules/Dashboard/types";
Expand All @@ -23,12 +25,15 @@ const toPublishmentStatus = (s: PublishmentStatus) =>
export default () => {
const [currentTeam, setLocalState] = useLocalState(s => s.currentTeam);
const navigate = useNavigate();
const intl = useIntl();

const [modalShown, setModalShown] = useState(false);
const openModal = useCallback(() => setModalShown(true), []);

const { data, loading, refetch } = useMeQuery();
const [createNewProject] = useCreateProjectMutation();
const [createNewProject] = useCreateProjectMutation({
refetchQueries: ["Project"],
});
const [createScene] = useCreateSceneMutation();

const teamId = currentTeam?.id;
Expand Down Expand Up @@ -84,29 +89,30 @@ export default () => {

// Submit Form
const createProject = useCallback(
async (data: { name: string; description: string }) => {
async (data: { name: string; description: string; imageUrl: string | null }) => {
if (!teamId) return;
const project = await createNewProject({
variables: {
teamId,
visualizer: Visualizer.Cesium,
name: data.name,
description: data.description,
imageUrl: data.imageUrl,
},
});
if (project.errors || !project.data?.createProject) {
throw new Error("プロジェクトの作成に失敗しました。"); // TODO: translate
throw new Error(intl.formatMessage({ defaultMessage: "Failed to create project." }));
}
const scene = await createScene({
variables: { projectId: project.data.createProject.project.id },
refetchQueries: ["Me"],
});
if (scene.errors || !scene.data) {
throw new Error("プロジェクトの作成に失敗しました。"); // TODO: translate
if (scene.errors || !scene.data?.createScene) {
throw new Error(intl.formatMessage({ defaultMessage: "Failed to create project." }));
}
setModalShown(false);
refetch();
},
[createNewProject, createScene, teamId],
[createNewProject, createScene, intl, refetch, teamId],
);

const selectProject = useCallback(
Expand All @@ -125,6 +131,21 @@ export default () => {
});
const assets = assetsData?.assets.nodes.filter(Boolean) as AssetNodes;

const [createAssetMutation] = useCreateAssetMutation();
const createAssets = useCallback(
(files: FileList) =>
(async () => {
if (teamId) {
await Promise.all(
Array.from(files).map(file =>
createAssetMutation({ variables: { teamId, file }, refetchQueries: ["Assets"] }),
),
);
}
})(),
[createAssetMutation, teamId],
);

return {
currentProjects,
archivedProjects,
Expand All @@ -136,5 +157,6 @@ export default () => {
createProject,
selectProject,
assets,
createAssets,
};
};
2 changes: 2 additions & 0 deletions src/components/organisms/Settings/ProjectList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ const ProjectList: React.FC<Props> = ({ teamId }) => {
createProject,
selectProject,
assets,
createAssets,
} = useHooks();

return (
Expand All @@ -42,6 +43,7 @@ const ProjectList: React.FC<Props> = ({ teamId }) => {
onClose={handleModalClose}
onSubmit={createProject}
assets={assets}
createAssets={createAssets}
/>
{loading && <Loading portal overlay />}
</SettingPage>
Expand Down