Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Style/fixes #108

Merged
merged 8 commits into from
Dec 18, 2024
118 changes: 69 additions & 49 deletions src/app/needs/next-actions/components/NextActionsDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import { useDatabase } from "@/context/DatabaseContext";
import clsx from "clsx";
import changeCase from "@/lib/utils/changeCase";
import NextActionsSection from "./NextActionsSection";
import Button from "@/ui/shared/Button";
import Modal from "@/ui/shared/Modal";
import { TrashIcon } from "@heroicons/react/24/outline";

export interface NeedDocument {
id: string;
Expand Down Expand Up @@ -34,15 +34,18 @@ export interface NextActionDocument {
export default function NextActionsDisplay() {
const database = useDatabase();
const [highlightedNeeds, setHighlightedNeeds] = useState<NeedDocument[]>([]);
const [relatedNextActions, setRelatedNextActions] = useState<NextActionDocument[]>([]);
const [relatedNextActions, setRelatedNextActions] = useState<
NextActionDocument[]
>([]);
const [chainEnd, setChainEnd] = useState(0);
const [actionState, setActionState] = useState(0);
const [mode, setMode] = useState<"create" | "destroy">("create");
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [choppingBlock, setChoppingBlock] = useState<NextActionDocument | null>(null);

const [choppingBlock, setChoppingBlock] = useState<NextActionDocument | null>(
null
);

useEffect(() => { /* Fetch Data */
useEffect(() => {
async function fetchData() {
const needsDocs = await database.getFromDb("needs");
const allNeeds = needsDocs.map((doc) => doc.toJSON() as NeedDocument);
Expand Down Expand Up @@ -73,9 +76,9 @@ export default function NextActionsDisplay() {
fetchData();
}, [database, chainEnd, actionState]);

useEffect(() => { /* Log Mode Change */
useEffect(() => {
console.log(`...to ${mode}.`);
}, [mode])
}, [mode]);

const priorityGroups = useMemo(() => {
if (highlightedNeeds.length === 0) return [];
Expand Down Expand Up @@ -126,7 +129,7 @@ export default function NextActionsDisplay() {
if (highlighted) {
const updatedTimestamps = [...action.selectedTimestamps];
updatedTimestamps.pop();

await database.updateDocument(
collectionName,
action.id,
Expand All @@ -141,9 +144,14 @@ export default function NextActionsDisplay() {
action.timestamp
);
} else {
const updatedTimestamps = [...action.selectedTimestamps, new Date().toISOString()];
const updatedTimestamps = [
...action.selectedTimestamps,
new Date().toISOString(),
];

const parentNeed = highlightedNeeds.find((need) => need.id === action.need);
const parentNeed = highlightedNeeds.find(
(need) => need.id === action.need
);
if (!parentNeed) {
console.error("Parent need not found for action:", action);
return;
Expand All @@ -164,7 +172,7 @@ export default function NextActionsDisplay() {
);
}

setChainEnd(prev => prev + 1);
setChainEnd((prev) => prev + 1);
};

const onDeleteAction = async (action: NextActionDocument) => {
Expand All @@ -176,11 +184,11 @@ export default function NextActionsDisplay() {
await database.deleteFromDb("next_actions", action.id);

setChoppingBlock(null);
setChainEnd(prev => prev + 1);
setChainEnd((prev) => prev + 1);
};

const onToggleMode = () => {
switch(mode) {
switch (mode) {
case "create":
setMode("destroy");
break;
Expand Down Expand Up @@ -211,35 +219,41 @@ export default function NextActionsDisplay() {
console.log(`Action State: ${actionState}`);
}
};

return (
<div className="w-11/12 m-auto">
{priorityGroups.length === 0
? (<p className="mb-5">
You have no unmet needs selected. Review which needs might be unmet before we can recommend next actions to meet them.
</p>)
: (priorityGroups.map((group, i) => (
{priorityGroups.length === 0 ? (
<p className="mb-5">
You have no unmet needs selected. Review which needs might be unmet
before we can recommend next actions to meet them.
</p>
) : (
priorityGroups.map((group, i) => (
<div key={i} className="mb-6">
<h3 className={clsx(
"text-xl font-bold mb-2",
{"text-twd-cube-red" : group.priority.order === 1 },
{"text-twd-cube-yellow" : group.priority.order === 2},
{"text-twd-cube-blue" : group.priority.order === 3},
{"text-twd-cube-green" : group.priority.order === 4}
)}>
<h3
className={clsx(
"text-xl font-bold mb-2",
{ "text-twd-cube-red": group.priority.order === 1 },
{ "text-twd-cube-yellow": group.priority.order === 2 },
{ "text-twd-cube-blue": group.priority.order === 3 },
{ "text-twd-cube-green": group.priority.order === 4 }
)}
>
{changeCase(group.priority.name, "sentence")}
</h3>

{group.needs.map((need) => {
const actions = getActionsForNeed(need.id);

return (
<div key={need.id}>
<h4 className="font-normal mb-4">
To meet a need for {changeCase(need.name, "lower")}, which actions can you take next?
To meet a need for {changeCase(need.name, "lower")}, which
actions can you take next?
</h4>

<NextActionsSection need={need}
<NextActionsSection
need={need}
actions={actions}
onToggleAction={onToggleAction}
onDeleteAction={onDeleteAction}
Expand All @@ -250,24 +264,28 @@ export default function NextActionsDisplay() {
);
})}
</div>
)))
}

<Button /* Mode Switcher */
label={"Delete Mode"}
onClick={() => {
console.log(`Toggling mode from ${mode}...`);
onToggleMode();
}}
className={clsx(
"fixed right-4 bottom-24 text-white rounded",
mode === "destroy"
? "bg-twd-primary-purple"
: "bg-gray-400 cursor-not-allowed"
)}
/>

<Modal title="Delete this action?"
))
)}

<button aria-label="Delete next actions">
<TrashIcon
className={clsx(
"w-16 h-16 fixed bottom-20 right-5 shadow-lg text-white p-4 rounded-full transform transition-all duration-200 ease-in-out",
{
"bg-gray-600": mode !== "destroy",
"bg-gradient-to-r from-twd-primary-purple to-purple-600":
mode === "destroy",
}
)}
onClick={() => {
console.log(`Toggling mode from ${mode}...`);
onToggleMode();
}}
/>
</button>

<Modal
title="Delete this action?"
modalOpen={isDeleteModalOpen}
forwardButton={{
action: () => {
Expand All @@ -279,10 +297,12 @@ export default function NextActionsDisplay() {
label: "Yes",
}}
backButton={{
action: () => { setIsDeleteModalOpen(false) },
action: () => {
setIsDeleteModalOpen(false);
},
label: "No",
}}
/>
</div>
);
}
}
78 changes: 41 additions & 37 deletions src/app/needs/next-actions/components/NextActionsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export default function NextActionsSection({
onToggleAction,
handleAddAction,
onDeleteAction,
mode
mode,
}: SectionProps) {
const [modalOpen, setModalOpen] = useState(false);
const [newAction, setNewAction] = useState<string>("");
Expand All @@ -38,60 +38,64 @@ export default function NextActionsSection({

return (
<>
{ actions.length > 0
? <div className="mb-6 flex gap-5 flex-wrap">
{actions.length > 0 ? (
<div className="mb-6 flex gap-5 flex-wrap">
{actions.map((action) => {
const highlighted = new Date(action.selectedExpiry) > new Date();

return (
<Button label={action.name}
<Button
label={action.name}
key={action.id}
className={ mode === "destroy"
? "bg-twd-cube-red text-black font-normal"
: highlighted
? "bg-twd-primary-purple text-black font-normal"
className={
mode === "destroy"
? "bg-twd-cube-red font-normal"
: highlighted
? "bg-twd-primary-purple font-normal"
: "bg-gray-600 text-white font-normal"
}
onClick={() => (mode === "destroy"
? onDeleteAction(action)
: onToggleAction(action)
)}
onClick={() =>
mode === "destroy"
? onDeleteAction(action)
: onToggleAction(action)
}
/>
);
})}

<button aria-label="Add Action"
<button
aria-label="Add Action"
onClick={() => setModalOpen(true)}
className="flex justify-center items-center"
>
<PlusCircleIcon className="w-7 m-auto"/>
<PlusCircleIcon className="w-7 m-auto" />
</button>
</div>
: (
<div className="flex gap-5 flex-wrap items-center">
<p className="text-sm text-gray-500 ml-6">
No next actions available for this need.
</p>
) : (
<div className="flex gap-5 flex-wrap items-center mb-5">
<p className="text-sm text-gray-500 ml-6">
No next actions available for this need.
</p>

<button aria-label="Add Action"
onClick={() => setModalOpen(true)}
className="flex justify-center items-center"
>
<PlusCircleIcon className="w-7 m-auto"/>
</button>
</div>
)
}
<button
aria-label="Add Action"
onClick={() => setModalOpen(true)}
className="flex justify-center items-center"
>
<PlusCircleIcon className="w-7 m-auto" />
</button>
</div>
)}

<Modal title="Add a New Action"
inputModal={ true }
modalOpen={ modalOpen }
<Modal
title="Add a New Action"
inputModal={true}
modalOpen={modalOpen}
placeholder="What action might help meet this need?"
handleInputChange={ handleInputChange }
forwardButton={{ label: "Add",
action: handleSubmitAction
}}
backButton={{ label: "Cancel",
handleInputChange={handleInputChange}
forwardButton={{ label: "Add", action: handleSubmitAction }}
backButton={{
label: "Cancel",
action: () => {
setNewAction("");
setModalOpen(false);
Expand All @@ -100,4 +104,4 @@ export default function NextActionsSection({
/>
</>
);
}
}
Loading