Skip to content

Commit

Permalink
🎉 feat: able to separate licenses (#333)
Browse files Browse the repository at this point in the history
  • Loading branch information
casperiv0 authored Jan 25, 2022
1 parent b44eede commit e3f27c1
Show file tree
Hide file tree
Showing 15 changed files with 185 additions and 51 deletions.
5 changes: 5 additions & 0 deletions packages/api/prisma/migrations/20220125150836_/migration.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- CreateEnum
CREATE TYPE "ValueLicenseType" AS ENUM ('LICENSE', 'REGISTRATION_STATUS');

-- AlterTable
ALTER TABLE "Value" ADD COLUMN "licenseType" "ValueLicenseType";
11 changes: 10 additions & 1 deletion packages/api/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,7 @@ model Weapon {

model MedicalRecord {
id String @id @default(cuid())
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
userId String?
citizen Citizen @relation(fields: [citizenId], references: [id], onDelete: Cascade)
citizenId String
Expand All @@ -261,6 +261,10 @@ model Value {
updatedAt DateTime @default(now()) @updatedAt
position Int?
// LICENSE type specific
// this was added here since the migration of eg `LicenseValue` would be to large.
licenseType ValueLicenseType?
// how to clean this up?!
ethnicityToValue Citizen[] @relation("ethnicityToValue")
genderToValue Citizen[] @relation("genderToValue")
Expand All @@ -284,6 +288,11 @@ model Value {
MedicalRecord MedicalRecord[]
}

enum ValueLicenseType {
LICENSE
REGISTRATION_STATUS
}

model PenalCode {
id String @id @default(cuid())
createdAt DateTime @default(now())
Expand Down
1 change: 1 addition & 0 deletions packages/api/src/controllers/admin/Values.ts
Original file line number Diff line number Diff line change
Expand Up @@ -424,6 +424,7 @@ export class ValuesController {
},
data: {
value: body.get("value"),
licenseType: type === "LICENSE" ? body.get("licenseType") : undefined,
},
});

Expand Down
2 changes: 2 additions & 0 deletions packages/api/src/controllers/admin/values/Import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
EmployeeAsEnum,
ShouldDoType,
StatusValueType,
ValueLicenseType,
} from "@prisma/client";
import { validateSchema } from "lib/validateSchema";

Expand Down Expand Up @@ -195,6 +196,7 @@ export const typeHandlers = {
isDefault: false,
type: type as ValueType,
value: item.value,
licenseType: type === "LICENSE" ? (item.licenseType as ValueLicenseType) : undefined,
},
});
}),
Expand Down
1 change: 1 addition & 0 deletions packages/client/locales/en/values.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
"addPenalCodeGroup": "Add Group",
"deleteGroup": "Delete Group",
"ungrouped": "Ungrouped",
"licenseType": "License Type",
"alert_deletePenalCodeGroup": "Are you sure you want to delete <span>{group}</span>? This action cannot be undone.",
"alert_deleteValue": "Are you sure you want to delete <span>{value}</span>? This action cannot be undone!"
},
Expand Down
45 changes: 44 additions & 1 deletion packages/client/src/components/admin/values/ManageValueModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import {
DriversLicenseCategoryType,
EmployeeAsEnum,
ShouldDoType,
ValueLicenseType,
ValueType,
} from "types/prisma";
import { useTranslations } from "use-intl";
Expand Down Expand Up @@ -69,13 +70,23 @@ export const DEPARTMENT_LABELS = {
[DepartmentType.EMS_FD]: "EMS/FD",
};

export const LICENSE_LABELS = {
[ValueLicenseType.LICENSE]: "License",
[ValueLicenseType.REGISTRATION_STATUS]: "Registration Status",
};

const SHOULD_DO_VALUES = Object.values(ShouldDoType).map((v) => ({
label: SHOULD_DO_LABELS[v],
value: v,
}));

const DEPARTMENT_TYPES = Object.values(DepartmentType).map((v) => ({
label: DEPARTMENT_LABELS[v],
label: DEPARTMENT_LABELS[v] as string,
value: v,
}));

const LICENSE_TYPES = Object.values(ValueLicenseType).map((v) => ({
label: LICENSE_LABELS[v] as string,
value: v,
}));

Expand Down Expand Up @@ -141,6 +152,8 @@ export function ManageValueModal({ onCreate, onUpdate, clType: dlType, type, val
type: value?.type ?? "STATUS_CODE",
// @ts-expect-error shortcut
hash: value?.hash ?? "",
// @ts-expect-error shortcut
licenseType: value?.licenseType ?? null,
showPicker: false,
};

Expand Down Expand Up @@ -186,6 +199,36 @@ export function ManageValueModal({ onCreate, onUpdate, clType: dlType, type, val
<Input autoFocus name="value" onChange={handleChange} value={values.value} />
</FormField>

{type === "LICENSE" ? (
<FormField errorMessage={errors.licenseType as string} label="Type">
<Select
isClearable
name="licenseType"
onChange={handleChange}
value={values.licenseType}
values={LICENSE_TYPES}
/>

<ul className="mt-5">
<li className="my-1.5 text-base italic">
- <b>None:</b>{" "}
{
/* eslint-disable-next-line quotes */
'Type is both a "License" and "Registration Status". Both can be used anywhere.'
}
</li>
<li className="my-1.5 text-base italic">
- <b>License:</b> can only be used as a license when setting a citizen drivers
license, firearms license, etc
</li>
<li className="my-1.5 text-base italic">
- <b>Registration Status:</b> can only be used when setting a registration
status on a vehicle or weapon.
</li>
</ul>
</FormField>
) : null}

{["DEPARTMENT", "DIVISION"].includes(type) ? (
<FormField optional label="Callsign Symbol">
<Input name="callsign" onChange={handleChange} value={values.callsign} />
Expand Down
27 changes: 16 additions & 11 deletions packages/client/src/components/citizen/ManageCitizenForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import { useAuth } from "context/AuthContext";
import { useValues } from "context/ValuesContext";
import { handleValidate } from "lib/handleValidate";
import { Formik, FormikHelpers } from "formik";
import { Citizen } from "types/prisma";
import { Citizen, ValueLicenseType } from "types/prisma";
import { useTranslations } from "next-intl";
import { Textarea } from "components/form/Textarea";
import { useFeatureEnabled } from "hooks/useFeatureEnabled";
import { filterLicenseTypes } from "lib/utils";

interface Props {
citizen: Citizen | null;
Expand Down Expand Up @@ -215,7 +216,7 @@ export function ManageCitizenForm({
<FormRow className="mt-5">
<FormField errorMessage={errors.driversLicense} label={t("driversLicense")}>
<Select
values={license.values.map((v) => ({
values={filterLicenseTypes(license.values, ValueLicenseType.LICENSE).map((v) => ({
label: v.value,
value: v.id,
}))}
Expand Down Expand Up @@ -248,10 +249,12 @@ export function ManageCitizenForm({
{WEAPON_REGISTRATION ? (
<FormField errorMessage={errors.weaponLicense} label={t("weaponLicense")}>
<Select
values={license.values.map((v) => ({
label: v.value,
value: v.id,
}))}
values={filterLicenseTypes(license.values, ValueLicenseType.LICENSE).map(
(v) => ({
label: v.value,
value: v.id,
}),
)}
value={values.weaponLicense}
onChange={handleChange}
name="weaponLicense"
Expand All @@ -261,7 +264,7 @@ export function ManageCitizenForm({

<FormField errorMessage={errors.pilotLicense} label={t("pilotLicense")}>
<Select
values={license.values.map((v) => ({
values={filterLicenseTypes(license.values, ValueLicenseType.LICENSE).map((v) => ({
label: v.value,
value: v.id,
}))}
Expand Down Expand Up @@ -290,10 +293,12 @@ export function ManageCitizenForm({
{WEAPON_REGISTRATION ? (
<FormField errorMessage={errors.ccw} label={t("ccw")}>
<Select
values={license.values.map((v) => ({
label: v.value,
value: v.id,
}))}
values={filterLicenseTypes(license.values, ValueLicenseType.LICENSE).map(
(v) => ({
label: v.value,
value: v.id,
}),
)}
value={values.ccw}
onChange={handleChange}
name="ccw"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import { handleValidate } from "lib/handleValidate";
import { useCitizen } from "context/CitizenContext";
import { FormRow } from "components/form/FormRow";
import { useFeatureEnabled } from "hooks/useFeatureEnabled";
import { filterLicenseTypes } from "lib/utils";
import { ValueLicenseType } from "types/prisma";

export function ManageLicensesModal() {
const { state, execute } = useFetch();
Expand Down Expand Up @@ -77,10 +79,12 @@ export function ManageLicensesModal() {
<FormRow>
<FormField errorMessage={errors.driversLicense} label={t("driversLicense")}>
<Select
values={license.values.map((license) => ({
label: license.value,
value: license.id,
}))}
values={filterLicenseTypes(license.values, ValueLicenseType.LICENSE).map(
(license) => ({
label: license.value,
value: license.id,
}),
)}
value={values.driversLicense}
name="driversLicense"
onChange={handleChange}
Expand Down Expand Up @@ -109,10 +113,12 @@ export function ManageLicensesModal() {
<FormRow>
<FormField errorMessage={errors.pilotLicense} label={t("pilotLicense")}>
<Select
values={license.values.map((license) => ({
label: license.value,
value: license.id,
}))}
values={filterLicenseTypes(license.values, ValueLicenseType.LICENSE).map(
(license) => ({
label: license.value,
value: license.id,
}),
)}
value={values.pilotLicense}
name="pilotLicense"
onChange={handleChange}
Expand Down Expand Up @@ -142,10 +148,12 @@ export function ManageLicensesModal() {
<>
<FormField errorMessage={errors.weaponLicense} label={t("weaponLicense")}>
<Select
values={license.values.map((license) => ({
label: license.value,
value: license.id,
}))}
values={filterLicenseTypes(license.values, ValueLicenseType.LICENSE).map(
(license) => ({
label: license.value,
value: license.id,
}),
)}
value={values.weaponLicense}
name="weaponLicense"
onChange={handleChange}
Expand All @@ -154,10 +162,12 @@ export function ManageLicensesModal() {

<FormField errorMessage={errors.ccw} label={t("ccw")}>
<Select
values={license.values.map((license) => ({
label: license.value,
value: license.id,
}))}
values={filterLicenseTypes(license.values, ValueLicenseType.LICENSE).map(
(license) => ({
label: license.value,
value: license.id,
}),
)}
value={values.ccw}
name="ccw"
onChange={handleChange}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import useFetch from "lib/useFetch";
import { useValues } from "src/context/ValuesContext";
import { useModal } from "context/ModalContext";
import { ModalIds } from "types/ModalIds";
import { Citizen, RegisteredVehicle } from "types/prisma";
import { Citizen, RegisteredVehicle, ValueLicenseType } from "types/prisma";
import { handleValidate } from "lib/handleValidate";
import { Input } from "components/form/inputs/Input";
import { useCitizen } from "context/CitizenContext";
Expand All @@ -19,6 +19,7 @@ import { useAuth } from "context/AuthContext";
import { Toggle } from "components/form/Toggle";
import { useFeatureEnabled } from "hooks/useFeatureEnabled";
import { useBusinessState } from "state/businessState";
import { filterLicenseTypes } from "lib/utils";

interface Props {
vehicle: RegisteredVehicle | null;
Expand Down Expand Up @@ -172,7 +173,10 @@ export function RegisterVehicleModal({
label={tVehicle("registrationStatus")}
>
<Select
values={license.values.map((license) => ({
values={filterLicenseTypes(
license.values,
ValueLicenseType.REGISTRATION_STATUS,
).map((license) => ({
label: license.value,
value: license.id,
}))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,12 @@ import useFetch from "lib/useFetch";
import { useValues } from "src/context/ValuesContext";
import { useModal } from "context/ModalContext";
import { ModalIds } from "types/ModalIds";
import { Citizen, Weapon } from "types/prisma";
import { Citizen, ValueLicenseType, Weapon } from "types/prisma";
import { handleValidate } from "lib/handleValidate";
import { useCitizen } from "context/CitizenContext";
import { Input } from "components/form/inputs/Input";
import { useFeatureEnabled } from "hooks/useFeatureEnabled";
import { filterLicenseTypes } from "lib/utils";

interface Props {
weapon: Weapon | null;
Expand Down Expand Up @@ -136,7 +137,10 @@ export function RegisterWeaponModal({ citizens = [], weapon, onClose, onCreate,
label={tVehicle("registrationStatus")}
>
<Select
values={license.values.map((license) => ({
values={filterLicenseTypes(
license.values,
ValueLicenseType.REGISTRATION_STATUS,
).map((license) => ({
label: license.value,
value: license.id,
}))}
Expand Down
Loading

0 comments on commit e3f27c1

Please sign in to comment.