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

Commit

Permalink
feat: public settings page (#32)
Browse files Browse the repository at this point in the history
Co-authored-by: rot1024 <aayhrot@gmail.com>
Co-authored-by: KaWaite <flippindaisy@gmail.com>
Co-authored-by: HideBa <49897538+HideBa@users.noreply.github.com>
  • Loading branch information
4 people committed Jul 16, 2021
1 parent 4cddcca commit ebfd416
Show file tree
Hide file tree
Showing 23 changed files with 662 additions and 618 deletions.
2 changes: 2 additions & 0 deletions src/app.tsx
Expand Up @@ -20,6 +20,7 @@ import AssetSettings from "@reearth/components/pages/Settings/Workspace/Asset";
import ProjectSettings from "@reearth/components/pages/Settings/Project";
import SettingsProjectList from "@reearth/components/pages/Settings/ProjectList";
import WorkspaceList from "@reearth/components/pages/Settings/WorkspaceList";
import PublicSettings from "@reearth/components/pages/Settings/Project/Public";
import DatasetSettings from "@reearth/components/pages/Settings/Project/Dataset";
import PluginSettings from "@reearth/components/pages/Settings/Project/Plugin";
import Preview from "./components/pages/Preview";
Expand Down Expand Up @@ -62,6 +63,7 @@ const App: React.FC = () => {
<SettingsProjectList path="/settings/workspace/:teamId/projects" />
<AssetSettings path="/settings/workspace/:teamId/asset" />
<ProjectSettings path="/settings/project/:projectId" />
<PublicSettings path="/settings/project/:projectId/public" />
<DatasetSettings path="/settings/project/:projectId/dataset" />
<PluginSettings path="/settings/project/:projectId/plugins" />
<NotFound default />
Expand Down
7 changes: 6 additions & 1 deletion src/components/molecules/Settings/Navigation/index.tsx
Expand Up @@ -15,6 +15,7 @@ type Team = {
type Project = {
id?: string;
name?: string;
isArchived?: boolean;
};

type Props = {
Expand Down Expand Up @@ -55,8 +56,12 @@ const Navigation: React.FC<Props> = ({ team, project }) => {
<NavigationItem
to={`/settings/workspace/${team?.id}/projects`}
name={intl.formatMessage({ defaultMessage: "Project List" })}>
{project && (
{project && !project.isArchived && (
<NavigationItem to={`/settings/project/${project.id}`} name={project.name as string}>
<NavigationItem
to={`/settings/project/${project.id}/public`}
name={intl.formatMessage({ defaultMessage: "Public" })}
/>
<NavigationItem
to={`/settings/project/${project.id}/dataset`}
name={intl.formatMessage({ defaultMessage: "Dataset" })}
Expand Down
Expand Up @@ -12,7 +12,7 @@ const ArchivedMessage: React.FC = () => {
<Description>
{intl.formatMessage({
defaultMessage:
"Most project settings are hidden for archived repositories. This project mus be unarchived to make changes to them.",
"Most project settings are hidden when the project is archived. Please unarchive the project to view and edit these settings.",
})}
</Description>
</Section>
Expand Down
16 changes: 11 additions & 5 deletions src/components/molecules/Settings/Project/DangerSection/index.tsx
Expand Up @@ -48,7 +48,13 @@ const DangerSection: React.FC<Props> = ({ project, teamId, archiveProject, delet
}
/>
<Divider /> */}
<Field header={intl.formatMessage({ defaultMessage: "Archive this project" })} />
<Field
header={
project?.isArchived
? intl.formatMessage({ defaultMessage: "Unarchive this project" })
: intl.formatMessage({ defaultMessage: "Archive this project" })
}
/>
<Field
body={
project?.isArchived
Expand All @@ -64,8 +70,8 @@ const DangerSection: React.FC<Props> = ({ project, teamId, archiveProject, delet
large
text={
project?.isArchived
? intl.formatMessage({ defaultMessage: "Unarchive this project" })
: intl.formatMessage({ defaultMessage: "Archive this project" })
? intl.formatMessage({ defaultMessage: "Unarchive project" })
: intl.formatMessage({ defaultMessage: "Archive project" })
}
onClick={() => openModal(project?.isArchived ? "unarchive" : "archive")}
buttonType="danger"
Expand All @@ -76,12 +82,12 @@ const DangerSection: React.FC<Props> = ({ project, teamId, archiveProject, delet
<Field header={intl.formatMessage({ defaultMessage: "Delete this project" })} />
<Field
body={intl.formatMessage({
defaultMessage: `Once you delete a project, there is no going back. Please be certain.`,
defaultMessage: `Once you delete a project, there is no going back. Please be sure.`,
})}
action={
<Button
large
text={intl.formatMessage({ defaultMessage: "Delete this project" })}
text={intl.formatMessage({ defaultMessage: "Delete project" })}
buttonType="danger"
onClick={() => openModal("delete")}
/>
Expand Down
Expand Up @@ -11,17 +11,17 @@ import DatasetList, {

type Props = {
datasetSchemas: Item[];
importDataset: (file: FileList) => void;
removeDatasetSchema: (schemaId: string) => void;
onDatasetImport?: (file: File, datasetSchemaId: string | null) => void | Promise<void>;
};

const DatasetSection: React.FC<Props> = ({
datasetSchemas,
importDataset,
removeDatasetSchema,
onDatasetImport,
}) => {
const intl = useIntl();
const handleFileSelect = useFileInput(files => importDataset?.(files), {
const handleFileSelect = useFileInput(files => onDatasetImport?.(files[0], null), {
multiple: false,
accept: "text/csv",
});
Expand Down
82 changes: 82 additions & 0 deletions src/components/molecules/Settings/Project/PublicSection/index.tsx
@@ -0,0 +1,82 @@
import React, { useCallback, useState } from "react";
import Section from "@reearth/components/molecules/Settings/Section";
import EditableItem from "@reearth/components/molecules/Settings/Project/EditableItem";
import AssetModal, { Asset as AssetType } from "@reearth/components/molecules/Common/AssetModal";
import { styled } from "@reearth/theme";
import { useIntl } from "react-intl";

export type Asset = AssetType;

export type Props = {
currentProject?: {
id: string;
publicTitle: string;
publicDescription: string;
publicImageUrl?: string;
};
updatePublicTitle?: (title: string) => void;
updatePublicDescription?: (description: string) => void;
updatePublicImage?: (imageUrl: string | null) => void;
assets?: Asset[];
createAssets?: (files: FileList) => Promise<void>;
};

const PublicSection: React.FC<Props> = ({
currentProject,
updatePublicTitle,
updatePublicDescription,
updatePublicImage,
assets,
createAssets,
}) => {
const intl = useIntl();
const [isAssetModalOpen, setAssetModalOpen] = useState(false);
const openAssetModal = useCallback(() => setAssetModalOpen(true), []);
const closeAssetModal = useCallback(() => setAssetModalOpen(false), []);

return (
<Wrapper>
<Section
title={intl.formatMessage({ defaultMessage: "Public Info" })}
subtitle={intl.formatMessage({
defaultMessage:
"(These fields will be used for OGP as well as metadata for the public project)",
})}>
<EditableItem
title={intl.formatMessage({ defaultMessage: "Title" })}
body={currentProject?.publicTitle}
onSubmit={updatePublicTitle}
/>
<EditableItem
title={intl.formatMessage({ defaultMessage: "Description" })}
body={currentProject?.publicDescription}
multilineTextBox={true}
onSubmit={updatePublicDescription}
/>
<EditableItem
title={intl.formatMessage({ defaultMessage: "Thumbnail" })}
onSubmit={updatePublicImage}
imageSrc={currentProject?.publicImageUrl as string}
isImage
onEditStart={() => openAssetModal()}
onEditCancel={() => closeAssetModal()}
/>
</Section>
<AssetModal
isOpen={isAssetModalOpen}
onClose={closeAssetModal}
assets={assets}
fileType="image"
onCreateAsset={createAssets}
onSelect={updatePublicImage}
value={currentProject?.publicImageUrl as string | undefined}
/>
</Wrapper>
);
};

const Wrapper = styled.div`
background-color: ${props => props.theme.colors.bg[3]};
`;

export default PublicSection;
Expand Up @@ -34,7 +34,6 @@ const PublishSection: React.FC<Props> = ({
}) => {
const url = window.REEARTH_CONFIG?.published?.split("{}");

// const [customUrlState, setCustomUrlState] = useState("");
const [showDModal, setDModal] = useState(false);
const intl = useIntl();
const theme = useTheme();
Expand Down Expand Up @@ -76,10 +75,14 @@ const PublishSection: React.FC<Props> = ({
{intl.formatMessage({ defaultMessage: "Site name" })}
</StyledText>
<Text size="s">
{intl.formatMessage({
defaultMessage:
"By default, once published your project will be accessible via the URL below.",
})}
{alias
? intl.formatMessage({
defaultMessage: "Access your project, copy or edit the URL below.",
})
: intl.formatMessage({
defaultMessage:
"Once your project is published from the editor page the URL details will be shown here.",
})}
</Text>
{alias && (
<StyledItem
Expand Down
40 changes: 23 additions & 17 deletions src/components/molecules/Settings/Section/index.tsx
@@ -1,47 +1,53 @@
import React from "react";
import { styled, useTheme } from "@reearth/theme";
import Text from "@reearth/components/atoms/Text";
import Flex from "@reearth/components/atoms/Flex";
import Divider from "@reearth/components/atoms/Divider";
import { metricsSizes } from "@reearth/theme/metrics";

export type Props = {
title?: string;
subtitle?: string;
actions?: React.ReactNode;
};

const Section: React.FC<Props> = ({ title, actions, children }) => {
const Section: React.FC<Props> = ({ title, subtitle, actions, children }) => {
const theme = useTheme();
return (
<div>
{title && (
<>
<SectionHeader>
<Text size="l" weight="normal" color={theme.main.strongText}>
{title}
</Text>
<SectionHeader justify="space-between">
<Flex direction="column">
<Text size="l" weight="normal" color={theme.main.strongText}>
{title}
</Text>
{subtitle && (
<Text
size="s"
weight="normal"
color={theme.main.text}
otherProperties={{ marginTop: metricsSizes["2xs"] + "px" }}>
{subtitle}
</Text>
)}
</Flex>
{actions}
</SectionHeader>
<Divider />
<Divider margin="0" />
</>
)}
<SectionItem>{children}</SectionItem>
<SectionItem direction="column">{children}</SectionItem>
</div>
);
};

const SectionHeader = styled.div`
const SectionHeader = styled(Flex)`
padding: ${metricsSizes["l"]}px ${metricsSizes["2xl"]}px;
display: flex;
justify-content: space-between;
`;

const SectionItem = styled.div`
const SectionItem = styled(Flex)`
padding: ${metricsSizes["l"]}px ${metricsSizes["2xl"]}px;
display: flex;
flex-direction: column;
`;

const Divider = styled.div`
border-bottom: ${props => `solid 1px ${props.theme.colors.outline.weak}`};
`;

export default Section;
Expand Up @@ -29,7 +29,7 @@ const DangerSection: React.FC<Props> = ({ team, deleteTeam }) => {
action={
<Button
large
text={intl.formatMessage({ defaultMessage: "Delete this workspace" })}
text={intl.formatMessage({ defaultMessage: "Delete workspace" })}
buttonType="danger"
onClick={() => setIsOpen(true)}
/>
Expand Down
51 changes: 37 additions & 14 deletions src/components/organisms/Settings/Project/Dataset/hooks.ts
Expand Up @@ -7,6 +7,7 @@ import {
useImportDatasetMutation,
useRemoveDatasetMutation,
} from "@reearth/gql";
import { useApolloClient } from "@apollo/client";

type Nodes = NonNullable<DatasetSchemasQuery["scene"]>["datasetSchemas"]["nodes"];

Expand All @@ -25,33 +26,55 @@ export default (projectId: string) => {

const sceneId = sceneData?.scene?.id;

const { data, refetch } = useDatasetSchemasQuery({
const { data } = useDatasetSchemasQuery({
variables: { projectId: projectId ?? "" },
skip: !projectId,
});

const nodes = data?.scene?.datasetSchemas.nodes ?? [];

const datasetSchemas = nodes.filter(Boolean) as DatasetSchemas;
const client = useApolloClient();

const [importDatasetMutation] = useImportDatasetMutation();

const importDataset = useCallback(
(file: FileList) => {
sceneId && importDatasetMutation({ variables: { file, sceneId } });
const [removeDatasetSchema] = useRemoveDatasetMutation();
const handleRemoveDataset = useCallback(
async (schemaId: string) => {
await removeDatasetSchema({
variables: {
schemaId,
force: true,
},
});
// re-render
await client.resetStore();
},
[sceneId, importDatasetMutation],
[client, removeDatasetSchema],
);

const [removeDatasetSchemaMutation] = useRemoveDatasetMutation();
// Add
const [importData] = useImportDatasetMutation();

const removeDatasetSchema = useCallback(
async (schemaId: string) => {
await removeDatasetSchemaMutation({ variables: { schemaId } });
await refetch();
const handleDatasetImport = useCallback(
async (file: File, schemeId: string | null) => {
if (!sceneId) return;
await importData({
variables: {
file,
sceneId,
datasetSchemaId: schemeId,
},
});
// re-render
await client.resetStore();
},
[removeDatasetSchemaMutation, refetch],
[client, importData, sceneId],
);

return { currentTeam, currentProject, datasetSchemas, importDataset, removeDatasetSchema };
return {
currentTeam,
currentProject,
datasetSchemas,
handleDatasetImport,
handleRemoveDataset,
};
};

0 comments on commit ebfd416

Please sign in to comment.