Skip to content

Commit 8add832

Browse files
Add Check functionality
1 parent 1f9b736 commit 8add832

8 files changed

Lines changed: 254 additions & 39 deletions

File tree

builder-api/src/main/java/org/acme/controller/EligibilityCheckResource.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ public Response createCheck(@Context SecurityIdentity identity,
7373

7474
//TODO: Add validations for user provided data
7575
newCheck.setOwnerId(userId);
76+
newCheck.setPublic(true); // By default all created checks are public
7677
try {
7778
String checkId = eligibilityCheckRepository.saveNewCheck(newCheck);
7879
newCheck.setId(checkId);

builder-api/src/main/java/org/acme/persistence/EligibilityCheckRepositoryImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ public List<EligibilityCheck> getChecksInBenefit(Benefit benefit){
5555
public String saveNewCheck(EligibilityCheck check) throws Exception{
5656
ObjectMapper mapper = new ObjectMapper().setSerializationInclusion(JsonInclude.Include.NON_NULL);
5757
Map<String, Object> data = mapper.convertValue(check, Map.class);
58-
String checkDocId = check.getModule() + "-" + check.getId();
58+
String checkDocId = check.getId();
5959
return FirestoreUtils.persistDocumentWithId(CollectionNames.ELIGIBILITY_CHECK_COLLECTION, checkDocId, data);
6060
}
6161

builder-frontend/src/api/check.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,30 @@ export const fetchCheck = async (checkId: string): Promise<EligibilityCheck> =>
4848
}
4949
};
5050

51+
52+
export const addCheck = async (check: EligibilityCheck) => {
53+
const url = apiUrl + "/check";
54+
try {
55+
const response = await authFetch(url, {
56+
method: "POST",
57+
headers: {
58+
"Content-Type": "application/json",
59+
Accept: "application/json",
60+
},
61+
body: JSON.stringify(check),
62+
});
63+
64+
if (!response.ok) {
65+
throw new Error(`Post failed with status: ${response.status}`);
66+
}
67+
const data = await response.json();
68+
return data;
69+
} catch (error) {
70+
console.error("Error creating new check:", error);
71+
throw error; // rethrow so you can handle it in your component if needed
72+
}
73+
};
74+
5175
export const fetchUserDefinedChecks = async (): Promise<EligibilityCheck[]> => {
5276
// Simulate an API call delay -- TODO: update to greater than 1ms delay
5377
await new Promise((resolve) => setTimeout(resolve, 1000));

builder-frontend/src/components/homeScreen/EligibilityChecksList.tsx

Lines changed: 0 additions & 37 deletions
This file was deleted.

builder-frontend/src/components/homeScreen/HomeScreen.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { createSignal, Match, Switch } from "solid-js";
2-
import EligibilityChecksList from "./EligibilityChecksList";
2+
3+
import EligibilityChecksList from "./eligibilityCheckList/EligibilityChecksList";
34
import ProjectsList from "./ProjectsList"
45
import Header from "../Header";
56

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import { createSignal, For, Show } from "solid-js";
2+
import { useNavigate } from "@solidjs/router";
3+
4+
import Loading from "@/components/Loading";
5+
import AddNewCheckModal from "./modals/AddNewCheckModal";
6+
import eligibilityCheckResource from "./eligibilityCheckResource";
7+
8+
import type { EligibilityCheck } from "@/types";
9+
10+
11+
const EligibilityChecksList = () => {
12+
const { checks, actions, actionInProgress, initialLoadStatus } = eligibilityCheckResource();
13+
const navigate = useNavigate();
14+
15+
const [addingNewCheck, setAddingNewCheck] = createSignal<boolean>(false);
16+
17+
const navigateToCheck = (check: EligibilityCheck) => {
18+
navigate("/check/" + check.id);
19+
}
20+
21+
return (
22+
<div class="p-4">
23+
<Show when={initialLoadStatus.loading() || actionInProgress()}>
24+
<Loading/>
25+
</Show>
26+
<div class="text-3xl font-bold mb-2 tracking-wide">
27+
Eligibility Checks
28+
</div>
29+
<div class="text-lg mb-3"> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
30+
</div>
31+
<div
32+
class="btn-default btn-blue mb-3 mr-1"
33+
onClick={() => {setAddingNewCheck(true)}}
34+
>
35+
Create New Check
36+
</div>
37+
<div class="flex flex-wrap gap-4">
38+
<For each={checks()}>
39+
{(check) => (
40+
<div
41+
class="border-2 border-gray-200 rounded p-4 w-60 hover:shadow-lg hover:bg-gray-200 cursor-pointer"
42+
onClick={() => navigateToCheck(check)}
43+
>
44+
<div class="text-lg font-bold text-gray-800">{check.name}</div>
45+
<div class="mt-2 text-gray-700">{check.description || "No description provided."}</div>
46+
</div>
47+
)}
48+
</For>
49+
</div>
50+
{
51+
addingNewCheck() &&
52+
<AddNewCheckModal
53+
closeModal={() => setAddingNewCheck(false)}
54+
addNewCheck={actions.addNewCheck}
55+
/>
56+
}
57+
</div>
58+
)
59+
};
60+
61+
export default EligibilityChecksList;
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { createResource, createEffect, Accessor, createSignal } from "solid-js";
2+
import { createStore } from "solid-js/store";
3+
4+
import type { EligibilityCheck } from "@/types";
5+
import { addCheck, fetchPublicChecks } from "@/api/check";
6+
7+
8+
export interface EligibilityCheckResource {
9+
checks: () => EligibilityCheck[];
10+
actions: {
11+
addNewCheck: (check: EligibilityCheck) => Promise<void>;
12+
removeCheck: (checkIdToRemove: string) => Promise<void>;
13+
};
14+
actionInProgress: Accessor<boolean>;
15+
initialLoadStatus: {
16+
loading: Accessor<boolean>;
17+
error: Accessor<unknown>;
18+
};
19+
}
20+
21+
const eligibilityCheckResource = (): EligibilityCheckResource => {
22+
const [checksResource, { refetch }] = createResource(fetchPublicChecks);
23+
const [actionInProgress, setActionInProgress] = createSignal<boolean>(false);
24+
25+
// Local fine-grained store
26+
const [checks, setChecks] = createStore<EligibilityCheck[]>([]);
27+
28+
// When resource resolves, sync it into the store
29+
createEffect(() => {
30+
if (checksResource()) {
31+
setChecks(checksResource()!);
32+
}
33+
});
34+
35+
// Actions
36+
const addNewCheck = async (check: EligibilityCheck) => {
37+
setActionInProgress(true);
38+
try {
39+
await addCheck(check);
40+
await refetch();
41+
} catch (e) {
42+
console.error("Failed to add new check", e);
43+
}
44+
setActionInProgress(false);
45+
}
46+
47+
const removeCheck = async (checkIdToRemove: string) => {
48+
setActionInProgress(true);
49+
try {
50+
// await removeCustomBenefit(screenerId(), benefitIdToRemove); TODO
51+
await refetch();
52+
} catch (e) {
53+
console.error("Failed to delete check", e);
54+
}
55+
setActionInProgress(false);
56+
};
57+
58+
return {
59+
checks: () => checks,
60+
actions: { addNewCheck, removeCheck },
61+
actionInProgress,
62+
initialLoadStatus: {
63+
loading: () => checksResource.loading,
64+
error: () => checksResource.error,
65+
},
66+
};
67+
};
68+
69+
export default eligibilityCheckResource;
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
import { createStore } from "solid-js/store"
2+
3+
import type { EligibilityCheck } from "@/types";
4+
5+
6+
type NewCheckValues = {
7+
name: string;
8+
module: string;
9+
description: string;
10+
}
11+
const AddNewCheckModal = (
12+
{ addNewCheck, closeModal }:
13+
{ addNewCheck: (check: EligibilityCheck) => Promise<void>; closeModal: () => void }
14+
) => {
15+
const [newCheck, setNewCheck] = createStore<NewCheckValues>({ name: "", module: "", description: "" });
16+
17+
// Styling for the Add button based on whether fields are filled
18+
const isAddDisabled = () => {
19+
return (
20+
newCheck.name.trim() === "" ||
21+
newCheck.description.trim() === "" ||
22+
newCheck.module.trim() === ""
23+
);
24+
}
25+
const addButtonClasses = () => {
26+
return isAddDisabled() ? "opacity-50 cursor-not-allowed" : "hover:bg-sky-700";
27+
}
28+
29+
return (
30+
<div class="fixed inset-0 bg-black/40 flex items-center justify-center z-50">
31+
<div class="bg-white px-12 py-8 rounded-xl max-w-140 w-1/2 min-w-80 min-h-96">
32+
<div class="text-2xl font-bold mb-4">Create New Check</div>
33+
<div class="mb-4">
34+
<label class="block font-bold mb-2">Name:</label>
35+
<input
36+
type="text"
37+
class="w-full border border-gray-300 rounded px-3 py-2"
38+
value={newCheck.name}
39+
onInput={(e) => setNewCheck("name", e.currentTarget.value)}
40+
placeholder="Enter check name"
41+
/>
42+
</div>
43+
<div class="mb-4">
44+
<label class="block font-bold mb-2">Module:</label>
45+
<input
46+
type="text"
47+
class="w-full border border-gray-300 rounded px-3 py-2"
48+
value={newCheck.module}
49+
onInput={(e) => setNewCheck("module", e.currentTarget.value)}
50+
placeholder="Enter check module"
51+
/>
52+
</div>
53+
<div class="mb-4">
54+
<label class="block font-bold mb-2">Description:</label>
55+
<textarea
56+
class="w-full border border-gray-300 rounded px-3 py-2"
57+
value={newCheck.description}
58+
onInput={(e) => setNewCheck("description", e.currentTarget.value)}
59+
placeholder="Enter check description"
60+
rows={4}
61+
/>
62+
</div>
63+
<div class="flex justify-end space-x-2">
64+
<div
65+
class="btn-default hover:bg-gray-200"
66+
onClick={() => { closeModal(); }}
67+
>
68+
Cancel
69+
</div>
70+
<div
71+
class={"btn-default bg-sky-600 text-white " + addButtonClasses()}
72+
onClick={async () => {
73+
if (isAddDisabled()) {
74+
console.log("Please fill in all fields.");
75+
return;
76+
}
77+
const check: EligibilityCheck = {
78+
id: newCheck.module.toLowerCase() + "-" + newCheck.name.toLowerCase(),
79+
name: newCheck.name,
80+
module: newCheck.module,
81+
description: newCheck.description,
82+
inputs: [],
83+
parameters: [],
84+
};
85+
await addNewCheck(check);
86+
closeModal();
87+
}}
88+
>
89+
Add Check
90+
</div>
91+
</div>
92+
</div>
93+
</div>
94+
);
95+
}
96+
export default AddNewCheckModal;

0 commit comments

Comments
 (0)