Skip to content

Commit

Permalink
fix delete button and url
Browse files Browse the repository at this point in the history
styling for sort controls

wire up sort and filters

update new SortControl with filteredFlows

fix sort changing showing all services

add delete button for search input

fix undefined values in selectFilters

fix handle delete on checkboxes

add clear filters buttons

init work on Stat app types and clearfilters

wire up clearFilters trigger and button
  • Loading branch information
RODO94 committed Jan 20, 2025
1 parent 73ca188 commit 51f236e
Show file tree
Hide file tree
Showing 7 changed files with 308 additions and 103 deletions.
1 change: 1 addition & 0 deletions api.planx.uk/modules/flows/publish/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { gql } from "graphql-request";
import type { FlowGraph, Node } from "@opensystemslab/planx-core/types";
import { userContext } from "../../auth/middleware.js";
import { getClient } from "../../../client/index.js";
import { getApplicationTypeVals } from "../validate/service/projectTypes.js";

interface PublishFlow {
publishedFlow: {
Expand Down
18 changes: 17 additions & 1 deletion api.planx.uk/modules/flows/validate/service/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ import { dataMerged, getMostRecentPublishedFlow } from "../../../../helpers.js";
import { validateFileTypes } from "./fileTypes.js";
import { validateInviteToPay } from "./inviteToPay.js";
import { validatePlanningConstraints } from "./planningConstraints.js";
import { validateProjectTypes } from "./projectTypes.js";
import { getApplicationTypeVals, validateProjectTypes } from "./projectTypes.js";
import { validateSections } from "./sections.js";
import { getValidSchemaValues } from "@opensystemslab/planx-core";

type AlteredNode = {
id: string;
Expand All @@ -29,12 +30,24 @@ interface FlowValidateAndDiffResponse {
alteredNodes: AlteredNode[] | null;
message: string;
validationChecks?: FlowValidationResponse[];
applicationTypes?: any;
isStatutoryApplication?:boolean;
trackerArray?: any;
}

const validateAndDiffFlow = async (
flowId: string,
): Promise<FlowValidateAndDiffResponse> => {
const flattenedFlow = await dataMerged(flowId);
const applicationTypes = getApplicationTypeVals(flattenedFlow)
const validApplicationTypes = getValidSchemaValues("ApplicationType");
const trackerArray: {value:string, result: boolean | undefined}[] = []
// What I want is, for the array of app types in the flow,
// do they all match with schema application type values?
const isStatutoryApplication = applicationTypes.some((value)=> {
const result = validApplicationTypes?.includes(value)
trackerArray.push({value: value, result: result})
return result })
const mostRecent = await getMostRecentPublishedFlow(flowId);

const delta = jsondiffpatch.diff(mostRecent, flattenedFlow);
Expand Down Expand Up @@ -80,6 +93,9 @@ const validateAndDiffFlow = async (
alteredNodes,
message: "Changes queued to publish",
validationChecks: sortedValidationChecks,
applicationTypes: applicationTypes,
isStatutoryApplication: isStatutoryApplication,
trackerArray: trackerArray
};
};

Expand Down
20 changes: 19 additions & 1 deletion api.planx.uk/modules/flows/validate/service/projectTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,22 @@ const getProjectTypeVals = (flowGraph: FlowGraph): string[] => {
return answerVals;
};

export { validateProjectTypes };
const getApplicationTypeVals = (flowGraph: FlowGraph): string[] => {
const applicationTypeChecklistNodes = Object.entries(flowGraph).filter(
(entry) =>
entry[1].data?.fn === "application.type",
);

const answerVals: string[] = [];
applicationTypeChecklistNodes.map(([_nodeId, node]) =>
node.edges?.map((edgeId) => {
if (typeof flowGraph[edgeId]?.data?.val === "string") {
answerVals.push(flowGraph[edgeId]?.data?.val);
}
}),
);

return answerVals;
};

export { validateProjectTypes, getApplicationTypeVals };
181 changes: 125 additions & 56 deletions editor.planx.uk/src/pages/Filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ const FiltersBody = styled(AccordionDetails)(({ theme }) => ({

const FiltersContent = styled(Box)(({ theme }) => ({
borderTop: `1px solid ${theme.palette.border.main}`,
padding: theme.spacing(2.5),
padding: theme.spacing(2.5, 2.5, 2, 2.5),
display: "flex",
flexDirection: "row",
flexWrap: "wrap",
Expand All @@ -97,11 +97,12 @@ interface FiltersProps {
flows: FlowSummary[];
setFilteredFlows: React.Dispatch<React.SetStateAction<FlowSummary[] | null>>;
formik: FormikProps<{ pattern: string; keys: string[] }>;
clearFilters: boolean;
}

interface FilterState {
status?: "online" | "offline";
applicationType?: "submission" | "guidance";
applicationType?: "submission";
serviceType?: "statutory" | "discretionary";
}

Expand All @@ -112,6 +113,7 @@ export const Filters: React.FC<FiltersProps> = ({
flows,
setFilteredFlows,
formik,
clearFilters,
}) => {
const [filters, setFilters] = useState<FilterState>();
const [selectedFilters, setSelectedFilters] = useState<
Expand All @@ -137,35 +139,86 @@ export const Filters: React.FC<FiltersProps> = ({
);

const addToSearchParams = (params: FilterState) => {
const newSearchParams = new URLSearchParams();
filters &&
Object.entries(params).forEach(([key, value]) => {
if (value) {
newSearchParams.set(key, value);
} else {
newSearchParams.delete(key);
}
});
const searchParams = new URLSearchParams(route.url.search);

// Update or remove filter parameters
Object.entries(params).forEach(([key, value]) => {
if (value) {
searchParams.set(key, value);
} else {
console.log("hitting delete");
searchParams.delete(key);
}
});

navigation.navigate(
{
pathname: window.location.pathname,
search: searchParams.toString(), // Use the complete searchParams object
},
{
replace: true,
},
);
};

const clearSearchParams = () => {
const searchParams = new URLSearchParams(route.url.search);
searchParams.delete("status");
searchParams.delete("applicationType");
searchParams.delete("serviceType");
navigation.navigate(
{
pathname: window.location.pathname,
search: newSearchParams.toString()
? `?${newSearchParams.toString()}`
: "",
search: searchParams.toString(), // Use the complete searchParams object
},
{
replace: true,
},
);
};

const clearAllFilters = () => {
setFilters({});
setSelectedFilters([]);
formik.setFieldValue("pattern", "");
clearSearchParams();
};

const handleFiltering = (filtersArg: FilterState | undefined) => {
// Get the results of the search
const { hasSearchResults, searchResults } = getSearchResults();
// if there's search results, filter those, if not, filter flows
const resultsToFilter = hasSearchResults ? searchResults : flows;

// this will filter the above by status or app type only for now
const filteredList = filterListByKeys(resultsToFilter);

if (filteredList) {
setFilteredFlows(filteredList);
}
if (
!filtersArg?.status &&
!filtersArg?.applicationType &&
!filtersArg?.serviceType &&
!hasSearchResults
) {
setFilteredFlows(flows);
}
};

useEffect(() => {
const params = route.url.query;
if (params) {
setFilters(params);
setSelectedFilters(Object.values(params));
handleFiltering(params);
const { status, applicationType, serviceType }: FilterState =
route.url.query;
const filtersToAssign = {
status: status,
applicationType: applicationType,
serviceType: serviceType,
};
if (status || applicationType || serviceType) {
setFilters(filtersToAssign);
setSelectedFilters(Object.values(filtersToAssign));
handleFiltering(filtersToAssign);
}
}, []);

Expand All @@ -177,7 +230,19 @@ export const Filters: React.FC<FiltersProps> = ({
if (!formik.values.pattern && filters) {
handleFiltering(filters);
}
}, [formik.values.pattern, search, debouncedSearch, results]);
}, [
formik.values.pattern,
search,
debouncedSearch,
results,
selectedFilters,
]);

useEffect(() => {
if (clearFilters) {
clearAllFilters();
}
}, [clearFilters]);

const getSearchResults = () => {
const searchResults = results.map((result) => result.item);
Expand All @@ -187,41 +252,37 @@ export const Filters: React.FC<FiltersProps> = ({
};
};

const handleFiltering = (filtersArg: FilterState | undefined) => {
// Get the results of the search
const { hasSearchResults, searchResults } = getSearchResults();
// if there's search results, filter those, if not, filter flows
const resultsToFilter = hasSearchResults ? searchResults : flows;
const filterListByKeys = (recordToFilter: FlowSummary[]) => {
if (!selectedFilters?.[0]) return recordToFilter;
const filteredResults = recordToFilter.filter((flow) => {
return selectedFilters.every((selectedFilterValue) => {
// Handle status filter
if (
selectedFilterValue === "online" ||
selectedFilterValue === "offline"
)
return flow.status === selectedFilterValue;

// this will filter the above by status only for now
const filterByStatus = resultsToFilter.filter((flow: FlowSummary) => {
if (filtersArg?.status) {
return flow.status === filtersArg.status;
} else {
// Handle applicationType (submission) filter
if (selectedFilterValue === "submission")
return flow.publishedFlows[0]?.hasSendComponent === true;
return true;
}
});
});
// update the list with the new filtered and searched flows
// if there's no search results, we will just filter by flows again
// flows stays constant
if (filterByStatus) {
setFilteredFlows(filterByStatus);
}
if (
!filtersArg?.status &&
!filtersArg?.applicationType &&
!filtersArg?.serviceType &&
!hasSearchResults
) {
setFilteredFlows(flows);
}
return filteredResults;
};

const handleChange = (filterKey: FilterKeys, filterValue: FilterValues) =>
filters?.[filterKey] === filterValue
? setFilters({ ...filters, [filterKey]: undefined })
? removeFilter(filterKey)
: setFilters({ ...filters, [filterKey]: filterValue });

const removeFilter = (targetFilter: FilterKeys) => {
const newFilters = { ...filters };
delete newFilters[targetFilter];
setFilters(newFilters);
};

return (
<FiltersContainer
expanded={expanded}
Expand Down Expand Up @@ -249,6 +310,14 @@ export const Filters: React.FC<FiltersProps> = ({
label={filter}
key={filter}
onDelete={() => {
const newSelectedFilters =
(selectedFilters.filter(
(selectedFilter) =>
selectedFilter !== filter &&
selectedFilter !== undefined,
) as string[]) || [];
console.log(newSelectedFilters);
setSelectedFilters(newSelectedFilters);
if (filters) {
const deleteFilter = Object.keys(filters) as FilterKeys[];
const targetFilter = deleteFilter.find(
Expand All @@ -258,11 +327,14 @@ export const Filters: React.FC<FiltersProps> = ({
);

if (targetFilter) {
setFilters({ ...filters, [targetFilter]: undefined });
handleFiltering({
const newFilters = { ...filters };
delete newFilters[targetFilter];
removeFilter(targetFilter);
addToSearchParams({
...filters,
[targetFilter]: undefined,
});
handleFiltering(newFilters);
}
}
}}
Expand Down Expand Up @@ -303,13 +375,6 @@ export const Filters: React.FC<FiltersProps> = ({
checked={filters?.applicationType === "submission"}
variant="compact"
/>
<ChecklistItem
onChange={() => handleChange("applicationType", "guidance")}
label={"Guidance"}
id={"guidance"}
checked={filters?.applicationType === "guidance"}
variant="compact"
/>
</FiltersColumn>
<FiltersColumn>
<Typography variant="h5" pb={0.5}>
Expand Down Expand Up @@ -339,7 +404,11 @@ export const Filters: React.FC<FiltersProps> = ({
if (filters) {
handleFiltering(filters);
addToSearchParams(filters);
setSelectedFilters(Object.values(filters));
setSelectedFilters(
Object.values(filters).filter(
(values) => values !== undefined,
),
);
}
}}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export const PublishFlowButton: React.FC<{ previewURL: string }> = ({
try {
setLastPublishedTitle("Checking for changes...");
const alteredFlow = await validateAndDiffFlow(flowId);
console.log(alteredFlow);
setAlteredNodes(
alteredFlow?.data.alteredNodes ? alteredFlow.data.alteredNodes : [],
);
Expand Down
Loading

0 comments on commit 51f236e

Please sign in to comment.