Skip to content

Commit

Permalink
Merge pull request #123 from mblajek/fz-58-facility-create
Browse files Browse the repository at this point in the history
FZ-58 Create facility flow
  • Loading branch information
qelo authored Oct 5, 2023
2 parents 703bd08 + b2bf87c commit 68a2793
Show file tree
Hide file tree
Showing 7 changed files with 142 additions and 3 deletions.
1 change: 1 addition & 0 deletions resources/js/data-access/memo-api/groups/Admin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export namespace Admin {
const queryClient = useQueryClient();
return {
users: () => queryClient.invalidateQueries({queryKey: keys.userLists()}),
facilities: () => queryClient.invalidateQueries({queryKey: keys.facilityLists()}),
};
}
}
37 changes: 37 additions & 0 deletions resources/js/features/facility-edit/FacilityCreateForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import {createMutation} from "@tanstack/solid-query";
import {useLangFunc} from "components/utils";
import {Admin, System} from "data-access/memo-api";
import {VoidComponent} from "solid-js";
import toast from "solid-toast";
import {FacilityForm, FacilityFormOutput} from "./FacilityForm";

interface Props {
onSuccess?: () => void;
onCancel?: () => void;
}

export const FacilityCreateForm: VoidComponent<Props> = (props) => {
const t = useLangFunc();
const adminInvalidator = Admin.useInvalidator();
const systemInvalidator = System.useInvalidator();
const facilityMutation = createMutation(() => ({
mutationFn: Admin.createFacility,
meta: {isFormSubmit: true},
}));

async function createFacility(values: FacilityFormOutput) {
await facilityMutation.mutateAsync({
name: values.name,
url: values.url,
});
adminInvalidator.facilities();
systemInvalidator.facilities();
toast.success(t("forms.facility_create.success"));
props.onSuccess?.();
}

return <FacilityForm id="facility_create" onSubmit={createFacility} onCancel={props.onCancel} />;
};

// For lazy loading
export default FacilityCreateForm;
26 changes: 26 additions & 0 deletions resources/js/features/facility-edit/FacilityCreateModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {useLangFunc} from "components/utils";
import {VoidComponent, createSignal, lazy} from "solid-js";
import {Modal as ModalComponent, MODAL_STYLE_PRESETS} from "components/ui";

const FacilityCreateForm = lazy(() => import("features/facility-edit/FacilityCreateForm"));

const [modalOpen, setModalOpen] = createSignal(false);

export const FacilityCreateModal: VoidComponent = () => {
const t = useLangFunc();
return (
<ModalComponent
title={t("forms.facility_create.formName")}
open={modalOpen()}
closeOn={["escapeKey", "closeButton"]}
onClose={() => setModalOpen(false)}
style={MODAL_STYLE_PRESETS.medium}
>
<FacilityCreateForm onSuccess={() => setModalOpen(false)} onCancel={() => setModalOpen(false)} />
</ModalComponent>
);
};

export function showFacilityCreateModal() {
setModalOpen(true);
}
55 changes: 55 additions & 0 deletions resources/js/features/facility-edit/FacilityForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import {FormConfigWithoutTransformFn} from "@felte/core";
import {FelteForm, FelteSubmit} from "components/felte-form";
import {TextField, getTrimInputHandler, trimInput} from "components/ui";
import {VoidComponent, createComputed, splitProps} from "solid-js";
import {z} from "zod";

/** Produces best effort suggestion for the url, e.g. "My Facility Name" --> "my-facility-name" */
function getUrlSuggestion(name: string) {
const url = trimInput(name).toLowerCase().replaceAll(" ", "-");
// Remove diacritics, especially for polish characters.
// https://stackoverflow.com/a/37511463/1832228
return url.normalize("NFD").replace(/\p{Diacritic}/gu, "").replace('ł', 'l');
}

const getSchema = () =>
z.object({
name: z.string(),
url: z.string(),
});

export type FacilityFormInput = z.input<ReturnType<typeof getSchema>>;
export type FacilityFormOutput = z.output<ReturnType<typeof getSchema>>;

type FormProps = FormConfigWithoutTransformFn<FacilityFormInput>;
type MyProps = {
onCancel?: () => void;
id: string;
};
type Props = FormProps & MyProps;

export const FacilityForm: VoidComponent<Props> = (props) => {
const [localProps, formProps]: [MyProps, FormProps] = splitProps(props, ["id", "onCancel"]);
return (
<FelteForm id={localProps.id} schema={getSchema()} {...formProps} class="flex flex-col gap-4">
{(form) => {
createComputed((lastSuggestion: string|undefined) => {
const suggestion = getUrlSuggestion(form.data("name") || '');
if (form.data("url") === lastSuggestion) {
form.setFields("url", suggestion);
}
return suggestion;
});
return (
<>
<div class="flex flex-col gap-1">
<TextField name="name" type="text" autocomplete="off" onBlur={getTrimInputHandler()} />
<TextField name="url" type="text" autocomplete="off" onBlur={getTrimInputHandler()} />
</div>
<FelteSubmit cancel={localProps.onCancel} />
</>
);
}}
</FelteForm>
);
};
15 changes: 13 additions & 2 deletions resources/js/features/root/pages/AdminFacilitiesList.page.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import {A} from "@solidjs/router";
import {createTableTranslations} from "components/ui";
import {Button, createTableTranslations} from "components/ui";
import {TQueryTable} from "components/ui/Table/TQueryTable";
import {AccessBarrier} from "components/utils";
import {AccessBarrier, useLangFunc} from "components/utils";
import {Admin} from "data-access/memo-api/groups/Admin";
import {FacilityCreateModal, showFacilityCreateModal} from "features/facility-edit/FacilityCreateModal";
import {BsHouseAdd} from "solid-icons/bs";
import {Component} from "solid-js";

export default (() => {
const t = useLangFunc();
return (
<AccessBarrier roles={["globalAdmin"]}>
<TQueryTable
Expand Down Expand Up @@ -50,7 +53,15 @@ export default (() => {
},
},
}}
customSectionBelowTable={
<div class="ml-2 flex gap-1">
<Button class="secondarySmall" onClick={() => showFacilityCreateModal()}>
<BsHouseAdd class="inlineIcon text-current" /> {t("actions.add_facility")}
</Button>
</div>
}
/>
<FacilityCreateModal />
</AccessBarrier>
);
}) satisfies Component;
1 change: 1 addition & 0 deletions resources/lang/pl_PL/actions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,4 @@ create: "Utwórz"
copy_to_clipboard: "Kopiuj do schowka"

add_user: "Dodaj użytkownika"
add_facility: "Dodaj placówkę"
10 changes: 9 additions & 1 deletion resources/lang/pl_PL/forms.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ user_edit:
success: "Pomyślnie zmieniono dane użytkownika"

user_create:
formName: "Dodawanie użytkownika"
formName: "Nowy użytkownik"
fieldNames:
name: "$t(models.user.name)"
email: "$t(models.user.email)"
Expand All @@ -44,3 +44,11 @@ user_create:
hasGlobalAdmin: "$t(models.user.hasGlobalAdmin)"
submit: "$t(actions.create)"
success: "Pomyślnie utworzono użytkownika"

facility_create:
formName: "Nowa placówka"
fieldNames:
name: "$t(models.facility.name)"
url: "$t(models.facility.url)"
submit: "$t(actions.create)"
success: "Pomyślnie utworzono placówkę"

0 comments on commit 68a2793

Please sign in to comment.