Skip to content

Commit

Permalink
feat(homebrew): Assets, moves, and oracles can now be moved between c…
Browse files Browse the repository at this point in the history
…ollections and categories
  • Loading branch information
scottbenton committed Apr 24, 2024
1 parent 460aef2 commit 37f64d4
Show file tree
Hide file tree
Showing 15 changed files with 772 additions and 106 deletions.
12 changes: 8 additions & 4 deletions src/components/features/assets/NewAssetCard/AssetHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@ import DeleteIcon from "@mui/icons-material/Delete";
export interface AssetHeaderProps {
asset: Datasworn.Asset;
onAssetRemove?: () => void;
actions?: React.ReactNode;
}

export function AssetHeader(props: AssetHeaderProps) {
const { asset, onAssetRemove } = props;
const { asset, onAssetRemove, actions } = props;

const isLocal = getIsLocalEnvironment();

Expand All @@ -36,10 +37,13 @@ export function AssetHeader(props: AssetHeaderProps) {
<LinkIcon color={"inherit"} />
</Tooltip>
)}
{actions}
{onAssetRemove && (
<IconButton color={"inherit"} onClick={onAssetRemove}>
<DeleteIcon />
</IconButton>
<Tooltip title={"Remove Asset"}>
<IconButton color={"inherit"} onClick={onAssetRemove}>
<DeleteIcon />
</IconButton>
</Tooltip>
)}
</Box>
</Box>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import { Datasworn } from "@datasworn/core";
import { Box, Card, IconButton, Tooltip } from "@mui/material";
import { AssetAbilities } from "components/features/assets/NewAssetCard/AssetAbilities";
import { AssetControls } from "components/features/assets/NewAssetCard/AssetControls";
import { AssetHeader } from "components/features/assets/NewAssetCard/AssetHeader";
import { AssetNameAndDescription } from "components/features/assets/NewAssetCard/AssetNameAndDescription";
import { AssetOptions } from "components/features/assets/NewAssetCard/AssetOptions";
import { convertIdPart } from "functions/dataswornIdEncoder";
import { StoredHomebrewAsset } from "types/homebrew/HomebrewAssets.type";
import EditIcon from "@mui/icons-material/Edit";
import MoveIcon from "@mui/icons-material/DriveFileMove";

export interface AssetPreviewCardProps {
storedAsset: StoredHomebrewAsset;
collectionName: string;
handleDeleteAsset: () => void;
handleEditAsset: () => void;
handleMoveAsset: () => void;
}

export function AssetPreviewCard(props: AssetPreviewCardProps) {
const {
storedAsset,
collectionName,
handleDeleteAsset,
handleEditAsset,
handleMoveAsset,
} = props;

const { label, requirement, abilities, options, controls } = storedAsset;

const dataswornAbilities: Datasworn.AssetAbility[] = abilities.map(
(ability, index) => ({
_id: index + "",
text: ability.text,
name: ability.name,
enabled: ability.defaultEnabled ?? false,
})
);

const dataswornOptions: Record<string, Datasworn.AssetOptionField> = {};
options?.forEach((option) => {
let optionId: string;

try {
optionId = convertIdPart(option.label);
} catch (e) {
return;
}
if (option.type === "text") {
dataswornOptions[optionId] = {
label: option.label,
field_type: "text",
value: "",
};
} else {
const choices: Record<string, Datasworn.SelectEnhancementFieldChoice> =
{};

(option.options ?? []).forEach((optionChoice) => {
choices[optionChoice] = {
label: optionChoice,
choice_type: "choice",
};
});

dataswornOptions[optionId] = {
label: option.label,
field_type: "select_enhancement",
value: "",
choices,
};
}
});

const dataswornControls: Record<string, Datasworn.AssetControlField> = {};
controls?.forEach((control) => {
let controlId: string;

try {
controlId = convertIdPart(control.label);
} catch (e) {
return;
}
if (control.type === "checkbox") {
dataswornControls[controlId] = {
field_type: "checkbox",
label: control.label,
value: false,
is_impact: false,
disables_asset: false,
};
} else if (control.type === "select") {
const choices: Record<string, Datasworn.SelectEnhancementFieldChoice> =
{};

(control.options ?? []).forEach((optionChoice) => {
choices[optionChoice] = {
label: optionChoice,
choice_type: "choice",
};
});

dataswornControls[controlId] = {
label: control.label,
field_type: "select_enhancement",
value: "",
choices,
};
} else if (control.type === "conditionMeter") {
dataswornControls[controlId] = {
label: control.label,
field_type: "condition_meter",
value: control.max,
max: control.max,
min: control.min,
rollable: true,
};
}
});

const asset: Datasworn.Asset = {
_id: "",
name: label,
count_as_impact: false,
shared: false,
_source: { title: "", authors: [], date: "", url: "", license: "" },

requirement: requirement,
category: collectionName,
abilities: dataswornAbilities,
options: dataswornOptions,
controls: dataswornControls,
};

return (
<Card
variant={"outlined"}
sx={{
position: "relative",
height: "100%",
display: "flex",
flexDirection: "column",
borderWidth: 0,
}}
>
<AssetHeader
asset={asset}
onAssetRemove={handleDeleteAsset}
actions={
<>
<Tooltip title={"Move asset to another collection"}>
<IconButton onClick={handleMoveAsset} color={"inherit"}>
<MoveIcon />
</IconButton>
</Tooltip>
<Tooltip title={"Edit Asset"}>
<IconButton onClick={handleEditAsset} color={"inherit"}>
<EditIcon />
</IconButton>
</Tooltip>
</>
}
/>
<Box
flexGrow={1}
display={"flex"}
flexDirection={"column"}
p={1}
border={(theme) => `1px solid ${theme.palette.divider}`}
sx={(theme) => ({
borderBottomLeftRadius: theme.shape.borderRadius,
borderBottomRightRadius: theme.shape.borderRadius,
})}
>
<AssetNameAndDescription asset={asset} />
<AssetOptions asset={asset} onAssetOptionChange={() => {}} />
<AssetAbilities asset={asset} />
<AssetControls controls={asset.controls} onControlChange={() => {}} />
</Box>
</Card>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import {
Autocomplete,
Box,
Button,
Dialog,
DialogActions,
DialogContent,
ListItemText,
TextField,
} from "@mui/material";
import { DialogTitleWithCloseButton } from "components/shared/DialogTitleWithCloseButton";
import { useEffect, useState } from "react";
import { useStore } from "stores/store";
import { StoredHomebrewAssetCollection } from "types/homebrew/HomebrewAssets.type";

export interface MoveAssetDialogProps {
onClose: () => void;
state?: {
assetId: string;
assetCollectionId: string;
};
collections: Record<string, StoredHomebrewAssetCollection>;
}

export function MoveAssetDialog(props: MoveAssetDialogProps) {
const { state, onClose, collections } = props;
const { assetId, assetCollectionId } = state ?? {};

const [selectedAssetCollection, setSelectedAssetCollection] =
useState(assetCollectionId);

useEffect(() => {
setSelectedAssetCollection(assetCollectionId);
}, [assetCollectionId]);

const updateAsset = useStore((store) => store.homebrew.updateAsset);

const handleSave = () => {
if (assetId && selectedAssetCollection) {
updateAsset(assetId, { categoryKey: selectedAssetCollection })
.then(() => {
onClose();
})
.catch(() => {});
}
};

return (
<Dialog open={!!assetId} onClose={onClose} maxWidth={"xs"} fullWidth>
<DialogTitleWithCloseButton onClose={onClose}>
Move Asset
</DialogTitleWithCloseButton>
<DialogContent>
<Autocomplete
sx={{ mt: 1 }}
options={Object.keys(collections)}
getOptionKey={(option) => option}
getOptionLabel={(key) => collections[key]?.label}
renderInput={(params) => (
<TextField {...params} label={"Asset Collections"} />
)}
renderOption={(props, option) => (
<Box component={"li"} {...props}>
<ListItemText primary={collections[option].label} />
</Box>
)}
value={selectedAssetCollection ?? null}
onChange={(evt, value) => {
setSelectedAssetCollection(value ?? undefined);
}}
/>
</DialogContent>
<DialogActions>
<Button color={"inherit"} onClick={onClose}>
Cancel
</Button>
<Button variant={"contained"} onClick={handleSave}>
Move Asset
</Button>
</DialogActions>
</Dialog>
);
}
Loading

0 comments on commit 37f64d4

Please sign in to comment.