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: next actions #97

Merged
merged 1 commit into from
Dec 17, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
111 changes: 61 additions & 50 deletions src/app/needs/next-actions/components/NextActionsDisplay.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,17 +32,20 @@ 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);

useEffect(() => { /* Fetch Data */
useEffect(() => {
/* Fetch Data */
async function fetchData() {
const needsDocs = await database.getFromDb("needs");
const allNeeds = needsDocs.map(doc => doc.toJSON() as NeedDocument);
const allNeeds = needsDocs.map((doc) => doc.toJSON() as NeedDocument);
const now = new Date();

const filteredNeeds = allNeeds.filter(need => {
const filteredNeeds = allNeeds.filter((need) => {
const expiry = new Date(need.selectedExpiry);
return expiry > now && need.priority && need.priority.order > 0;
});
Expand All @@ -52,15 +55,13 @@ export default function NextActionsDisplay() {
const nextActionsDocs = await database.getFromDb("next_actions");

const allNextActions = nextActionsDocs.map(
doc => doc.toJSON() as NextActionDocument
(doc) => doc.toJSON() as NextActionDocument
);

const highlightedNeedIds = new Set(filteredNeeds.map(
need => need.id
));
const highlightedNeedIds = new Set(filteredNeeds.map((need) => need.id));

const filteredNextActions = allNextActions.filter(
action => highlightedNeedIds.has(action.need)
const filteredNextActions = allNextActions.filter((action) =>
highlightedNeedIds.has(action.need)
);

setRelatedNextActions(filteredNextActions);
Expand All @@ -73,28 +74,31 @@ export default function NextActionsDisplay() {
if (highlightedNeeds.length === 0) return [];

const needsWithPriority = highlightedNeeds.filter(
need => need.priority && need.priority.order
(need) => need.priority && need.priority.order
);

const sortedNeeds = needsWithPriority.sort((a, b) =>
a.priority!.order - b.priority!.order
const sortedNeeds = needsWithPriority.sort(
(a, b) => a.priority!.order - b.priority!.order
);

const groupsMap: Record<number, {
priority: {
order: number;
name: string;
};
needs: NeedDocument[]
}> = {};
const groupsMap: Record<
number,
{
priority: {
order: number;
name: string;
};
needs: NeedDocument[];
}
> = {};

for (const need of sortedNeeds) {
const order = need.priority!.order;

if (!groupsMap[order]) {
groupsMap[order] = {
priority: need.priority!,
needs: []
needs: [],
};
}

Expand All @@ -105,7 +109,7 @@ export default function NextActionsDisplay() {
}, [highlightedNeeds]);

const getActionsForNeed = (needId: string) => {
return relatedNextActions.filter(action => action.need === needId);
return relatedNextActions.filter((action) => action.need === needId);
};

const onToggleAction = async (action: NextActionDocument) => {
Expand All @@ -115,7 +119,7 @@ export default function NextActionsDisplay() {
if (highlighted) {
const updatedTimestamps = [...action.selectedTimestamps];
updatedTimestamps.pop();

await database.updateDocument(
collectionName,
action.id,
Expand All @@ -132,10 +136,15 @@ export default function NextActionsDisplay() {
} else {
// Highlight action:
// Add new selectedTimestamp
const updatedTimestamps = [...action.selectedTimestamps, new Date().toISOString()];
const updatedTimestamps = [
...action.selectedTimestamps,
new Date().toISOString(),
];

// Find the parent need to copy its selectedExpiry
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 @@ -156,7 +165,7 @@ export default function NextActionsDisplay() {
);
}

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

const handleAddAction = async (newAction: string, need: NeedDocument) => {
Expand All @@ -168,48 +177,51 @@ export default function NextActionsDisplay() {
selectedTimestamps: [],
selectedExpiry: new Date().toISOString(),
timestamp: new Date().toISOString(),
}
};
try {
await database.addToDb("next_actions", newActionDocument);
console.log(`Action Created: ${newActionDocument.name}`);
} catch (error) {
console.error("Error creating Action:", error);
}
setActionState(prev => prev + 1);

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

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}
{ "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} className="ml-4 mb-4">
<h4 className="font-semibold">
To meet a need for {changeCase(need.name, "lower")}, which actions can you take next?
<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?
</h4>

{ actions.length > 0 ? (
{actions.length > 0 ? (
<NextActionsSection
need={need}
actions={actions}
Expand All @@ -220,14 +232,13 @@ export default function NextActionsDisplay() {
<p className="text-sm text-gray-500 ml-6">
No next actions available for this need.
</p>
)
}
</div>
)}
</div>
);
})}
</div>
)))
}
))
)}
</div>
);
}
}
85 changes: 46 additions & 39 deletions src/app/needs/next-actions/components/NextActionsSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,51 +24,58 @@ export default function NextActionsSection({
const [newAction, setNewAction] = useState<string>("");

const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setNewAction(e.target.value)
setNewAction(e.target.value);
};

const handleSubmitAction = async () => {
await handleAddAction(newAction, need);
setModalOpen(false);
}
};

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

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

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

<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",
action: () => {
setNewAction("");
setModalOpen(false);
},
}}
/>
</> );
}
<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",
action: () => {
setNewAction("");
setModalOpen(false);
},
}}
/>
</>
);
}
Loading