Skip to content

Commit

Permalink
refactor: Wrote a CardEditor to prevent writing Cards twice
Browse files Browse the repository at this point in the history
  • Loading branch information
Vexcited committed Apr 22, 2022
1 parent ade51d6 commit 8b2fc88
Show file tree
Hide file tree
Showing 4 changed files with 286 additions and 237 deletions.
194 changes: 194 additions & 0 deletions src/components/ProjectEditor/CardEditor.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
import type { ProjectData, ProjectDataSample } from "@/types/Project";
import type { ChangeEvent } from "react";

// Stores
import { useUnsavedProjectStore } from "@/stores/unsaved_project";

// Components
import Select from "@/components/Select";
import Input from "@/components/Input";
import { Fragment } from "react";

// Icons
import {
HiOutlinePlus,
HiOutlineTrash,
HiArrowDown,
HiArrowUp
} from "react-icons/hi";

interface CardEditorProps {
handleSelection: (evt: ChangeEvent<HTMLSelectElement>) => void;
selectorItems:
| ProjectData["launchpads"][number]["pages"]
| ProjectData["launchpads"]
;

type: "launchpad" | "page";
launchpad: ProjectData["launchpads"][number] & { id: number } | null;

target:
| ProjectData["launchpads"][number] & { id: number } | null
| ProjectData["launchpads"][number]["pages"][number] & { id: number } | null

addToSelector: () => void,
removeFromSelector: () => void,

upItem: () => void,
downItem: () => void,

children: React.ReactNode
}

export default function CardEditor ({
handleSelection,
selectorItems,

type,
launchpad,
target,

addToSelector,
removeFromSelector,

upItem,
downItem,

children
}: CardEditorProps) {
const { data, setData } = useUnsavedProjectStore();
if (!data) return <p>Loading...</p>;

return (
<div className="
flex flex-col sm:flex-row gap-4 p-4
bg-gray-700 rounded-lg w-fit mx-auto
">
<div className="
max-w-xs sm:w-60 md:w-64 m-auto flex flex-col gap-4
">
<div className="
flex gap-2 justify-around
">
<Select
value={target?.id}
onChange={handleSelection}

placeholder={`Select a ${type}`}
title={`Select a ${type}`}
>
{selectorItems.map((item, itemKey) =>
<option value={itemKey} key={itemKey}>
{item.name}
</option>
)}
</Select>

<button
className="
whitespace-nowrap px-4 py-2 rounded-lg
text-gray-300
hover:bg-blue-600
bg-gray-900 bg-opacity-20
border border-gray-900 hover:border-blue-500
transition-all
"

onClick={addToSelector}
title={`Add a ${type} to the project`}
>
<HiOutlinePlus size={18} />
</button>
</div>

{children}

<div className="
flex gap-2 justify-around
">
{target
? (
<Fragment>
{target.id !== 0 && (
<button
className="
px-4 py-2 rounded-lg w-full flex justify-center
text-gray-300 hover:text-blue-600
bg-gray-900 bg-opacity-20 hover:bg-opacity-60
border border-gray-900 hover:border-blue-600
"

title={`Move the current ${type} up`}
onClick={upItem}
>
<HiArrowUp size={18} />
</button>
)}

<button
className="
px-4 py-2 rounded-lg w-full flex justify-center
text-gray-300 hover:text-pink-600
bg-gray-900 bg-opacity-20 hover:bg-opacity-60
border border-gray-900 hover:border-pink-600
"

title={`Remove the current ${type}`}
onClick={removeFromSelector}
>
<HiOutlineTrash size={18} />
</button>

{launchpad && target.id !== ((type === "launchpad" ? data.launchpads : launchpad.pages).length - 1) && (
<button
className="
px-4 py-2 rounded-lg w-full flex justify-center
text-gray-300 hover:text-blue-600
bg-gray-900 bg-opacity-20 hover:bg-opacity-60
border border-gray-900 hover:border-blue-600
"

title={`Move the current ${type} down`}
onClick={downItem}
>
<HiArrowDown size={18} />
</button>
)}
</Fragment>
)
: (
<p className="
text-gray-300
px-4 py-2 rounded-lg
bg-gray-900 bg-opacity-40
h-fit my-auto
">
No {type} selected
</p>
)
}
</div>

{launchpad && target && (
<Input
placeholder={target.name}
value={target.name}
onChange={evt => {
const data_copy = { ...data };

if (type === "launchpad") {
data_copy.launchpads[target.id].name = evt.target.value;
}
else if (type === "page") {
data_copy.launchpads[launchpad.id].pages[target.id].name = evt.target.value;
}
else return;

setData(data_copy);
}}
/>
)}
</div>
</div>
);
}
166 changes: 66 additions & 100 deletions src/components/ProjectEditor/LaunchpadEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,10 @@ import { useUnsavedProjectStore } from "@/stores/unsaved_project";

// Components
import Launchpad from "@/components/Launchpad";
import Select from "@/components/Select";
import Input from "@/components/Input";
import { Fragment } from "react";

// Icons
import { HiOutlinePlus, HiOutlineTrash } from "react-icons/hi";
import CardEditor from "./CardEditor";

interface LaunchpadEditorProps {
setCurrentLaunchpadSelected: (id: number) => void;
handleLaunchpadSelection: (evt: ChangeEvent<HTMLSelectElement>) => void,
launchpad: ProjectData["launchpads"][number] & { id: number } | null,
sample: ProjectDataSample & { id: number } | null,
Expand All @@ -28,6 +24,7 @@ interface LaunchpadEditorProps {
}

export default function LaunchpadEditor ({
setCurrentLaunchpadSelected,
handleLaunchpadSelection,
launchpad,
sample,
Expand Down Expand Up @@ -60,100 +57,69 @@ export default function LaunchpadEditor ({
const { data, setData } = useUnsavedProjectStore();
if (!data) return <p>Loading...</p>;

/** Remove `1` to the launchpad index. */
const upLaunchpad = () => {
if (!launchpad) return;
const data_copy = { ...data };
const launchpads_copy = [...data_copy.launchpads];
const launchpad_copy = { ...launchpads_copy[launchpad.id] };
const launchpad_id = launchpad.id;

if (launchpad_id === 0) return;

launchpads_copy[launchpad_id] = launchpads_copy[launchpad_id - 1];
launchpads_copy[launchpad_id - 1] = launchpad_copy;

data_copy.launchpads = launchpads_copy;
setData(data_copy);

setCurrentLaunchpadSelected(launchpad_id - 1);
};

/** Add `1` to the launchpad index. */
const downLaunchpad = () => {
if (!launchpad) return;
const data_copy = { ...data };
const launchpads_copy = [...data_copy.launchpads];
const launchpad_copy = { ...launchpads_copy[launchpad.id] };
const launchpad_id = launchpad.id;

if (launchpad_id === launchpads_copy.length - 1) return;

launchpads_copy[launchpad_id] = launchpads_copy[launchpad_id + 1];
launchpads_copy[launchpad_id + 1] = launchpad_copy;

data_copy.launchpads = launchpads_copy;
setData(data_copy);

setCurrentLaunchpadSelected(launchpad_id + 1);
};

return (
<div className="
flex flex-col sm:flex-row gap-4 p-4
bg-gray-700 rounded-lg w-fit mx-auto
">
<div className="
max-w-xs sm:w-60 md:w-64 m-auto flex flex-col gap-4
">
<div className="
flex gap-2 justify-around
">
<Select
value={launchpad?.id}
onChange={handleLaunchpadSelection}

placeholder="Select a launchpad"
title="Select a launchpad"
>
{data.launchpads.map((launchpad, launchpadKey) =>
<option value={launchpadKey} key={launchpadKey}>
{launchpad.name}
</option>
)}
</Select>

<button
className="
whitespace-nowrap px-4 py-2 rounded-lg
text-gray-300
hover:bg-blue-600
bg-gray-900 bg-opacity-20
border border-gray-900 hover:border-blue-500
transition-all
"

onClick={addLaunchpad}
title="Add a launchpad to the project"
>
<HiOutlinePlus size={18} />
</button>
</div>

{launchpad && (
<Launchpad
ref={launchpadRef}
layout="programmer"
onPadUp={() => null}
onPadDown={pad_id => handleLaunchpadClick(pad_id)}
/>
)}

<div className="
flex gap-2 justify-around
">
{launchpad
? (
<Fragment>
<Input
placeholder={launchpad.name}
value={launchpad.name}
onChange={evt => {
const data_copy = { ...data };
data_copy.launchpads[launchpad.id].name = evt.target.value;
setData(data_copy);
}}
/>

<button
className="
px-4 py-2 rounded-lg
text-gray-300 hover:text-pink-600
bg-gray-900 bg-opacity-20 hover:bg-opacity-60
border border-gray-900 hover:border-pink-600
"

onClick={removeLaunchpad}
title="Remove current launchpad"
>
<HiOutlineTrash size={18} />
</button>
</Fragment>
)
: (
<p className="
text-gray-300
px-4 py-2 rounded-lg
bg-gray-900 bg-opacity-40
">
No launchpad selected
</p>
)
}
</div>
</div>
</div>
<CardEditor
type="launchpad"
launchpad={launchpad}
target={launchpad}

addToSelector={addLaunchpad}
removeFromSelector={removeLaunchpad}

selectorItems={data.launchpads}
handleSelection={handleLaunchpadSelection}

upItem={upLaunchpad}
downItem={downLaunchpad}
>

{launchpad && (
<Launchpad
ref={launchpadRef}
layout="programmer"
onPadUp={() => null}
onPadDown={pad_id => handleLaunchpadClick(pad_id)}
/>
)}

</CardEditor>
);
}
Loading

0 comments on commit 8b2fc88

Please sign in to comment.