Merge branch into logestic_chnage, resolve licensing-api tag conflict

Kept both new cache tags (PickupOffice/PickupAppointment from this
branch, Department/Rank from origin) — additive, not conflicting.
This commit is contained in:
fitse-yotor
2026-08-28 15:51:09 +03:00
92 changed files with 5305 additions and 1041 deletions

View File

@@ -6,6 +6,7 @@ import type {
ApplicationPayment,
ApplicationStaff,
Attachment,
Department,
DocumentRequirement,
FormSchemaPalette,
FormSectionConfig,
@@ -22,6 +23,7 @@ import type {
AssignableOfficer,
DocumentDecision,
DocumentReview,
EligibleExam,
ExportResult,
LicenseTemplate,
Paginated,
@@ -30,6 +32,8 @@ import type {
PickupSlot,
QueueCounts,
QueueFilter,
Rank,
RankCertificateCategory,
RemarkTargetType,
SavedQueueView,
SchemaIssue,
@@ -77,6 +81,8 @@ const TAGS = [
'DocumentRequirement',
'PickupOffice',
'PickupAppointment',
'Department',
'Rank',
] as const;
const listTag = (type: (typeof TAGS)[number]) => ({ type, id: 'LIST' }) as const;
@@ -259,6 +265,75 @@ export const licensingApi = baseApi
invalidatesTags: (_r, error) => (error ? [] : [listTag('DocumentRequirement')]),
}),
// --------------------------------------------------- departments & ranks
/** Every department, for the admin editor. */
getDepartments: builder.query<Paginated<Department>, void>({
query: () => ({ url: '/departments' }),
providesTags: () => [listTag('Department')],
}),
/** Active departments only — the applicant-facing picker. */
getActiveDepartments: builder.query<Department[], void>({
query: () => ({ url: '/departments/active/list' }),
providesTags: () => [listTag('Department')],
}),
createDepartment: builder.mutation<
Department,
Partial<Department> & { code: string; name: Department['name'] }
>({
query: (body) => ({ url: '/departments', method: 'POST', body }),
invalidatesTags: (_r, error) => (error ? [] : [listTag('Department')]),
}),
updateDepartment: builder.mutation<Department, { id: string } & Partial<Department>>({
query: ({ id, ...body }) => ({ url: `/departments/${id}`, method: 'PUT', body }),
invalidatesTags: (_r, error) => (error ? [] : [listTag('Department')]),
}),
deleteDepartment: builder.mutation<unknown, string>({
query: (id) => ({ url: `/departments/${id}`, method: 'DELETE' }),
invalidatesTags: (_r, error) => (error ? [] : [listTag('Department')]),
}),
/** Every rank, for the admin editor to filter/group by department client-side. */
getRanks: builder.query<Paginated<Rank>, void>({
query: () => ({ url: '/ranks' }),
providesTags: () => [listTag('Rank')],
}),
/** One department's ladder for a category, ordered — the applicant wizard's rank picker. */
getRankLadder: builder.query<
Rank[],
{ departmentId: string; certificateCategory: RankCertificateCategory }
>({
query: (params) => ({ url: '/ranks/ladder', params }),
providesTags: () => [listTag('Rank')],
}),
createRank: builder.mutation<
Rank,
Partial<Rank> & {
departmentId: string;
certificateCategory: RankCertificateCategory;
key: string;
name: Rank['name'];
}
>({
query: (body) => ({ url: '/ranks', method: 'POST', body }),
invalidatesTags: (_r, error) => (error ? [] : [listTag('Rank')]),
}),
updateRank: builder.mutation<Rank, { id: string } & Partial<Rank>>({
query: ({ id, ...body }) => ({ url: `/ranks/${id}`, method: 'PUT', body }),
invalidatesTags: (_r, error) => (error ? [] : [listTag('Rank')]),
}),
deleteRank: builder.mutation<unknown, string>({
query: (id) => ({ url: `/ranks/${id}`, method: 'DELETE' }),
invalidatesTags: (_r, error) => (error ? [] : [listTag('Rank')]),
}),
// -------------------------------------------------------- application
createApplication: builder.mutation<
LicenseApplication,
@@ -581,6 +656,15 @@ export const licensingApi = baseApi
error ? [] : [itemTag('LicenseApplication', id), listTag('ApplicationQueue')],
}),
/**
* Exam sittings valid for this application's rank — what the
* schedule-exam picker offers, instead of every exam in the system.
*/
getEligibleExams: builder.query<EligibleExam[], string>({
query: (id) => ({ url: `/license-application-review/${id}/eligible-exams` }),
providesTags: (_r, _e, id) => [itemTag('LicenseApplication', id)],
}),
/** Places a candidate who has paid the examination fee into a sitting. */
scheduleExam: builder.mutation<
LicenseApplication,
@@ -647,6 +731,8 @@ export const licensingApi = baseApi
LicenseTemplate,
{
licenseTypeId: string;
/** Scopes the draft to one rank's certificate. Omit for the type's default design. */
rankId?: string | null;
name: string;
hbsSource?: string;
pageOptions?: TemplatePageOptions;
@@ -660,6 +746,7 @@ export const licensingApi = baseApi
LicenseTemplate,
{
id: string;
rankId?: string | null;
name?: string;
hbsSource?: string;
pageOptions?: TemplatePageOptions;
@@ -845,6 +932,23 @@ export const licensingApi = baseApi
error ? [] : [itemTag('LicenseApplication', id), listTag('ApplicationQueue')],
}),
/**
* Starts the review: the team leader hands the file to an employee.
* `assign` above only re-points an application already in flight.
*/
assignReviewer: builder.mutation<
LicenseApplication,
{ id: string; officerId: string; remark?: string }
>({
query: ({ id, ...body }) => ({
url: `/license-application-review/${id}/assign-reviewer`,
method: 'POST',
body,
}),
invalidatesTags: (_r, error, { id }) =>
error ? [] : [itemTag('LicenseApplication', id), listTag('ApplicationQueue')],
}),
holdApplication: builder.mutation<
LicenseApplication,
{ id: string; reason: string }
@@ -1088,6 +1192,16 @@ export const {
useCreateDocumentRequirementMutation,
useUpdateDocumentRequirementMutation,
useDeleteDocumentRequirementMutation,
useGetDepartmentsQuery,
useGetActiveDepartmentsQuery,
useCreateDepartmentMutation,
useUpdateDepartmentMutation,
useDeleteDepartmentMutation,
useGetRanksQuery,
useGetRankLadderQuery,
useCreateRankMutation,
useUpdateRankMutation,
useDeleteRankMutation,
useUpdateLicenseValidityMutation,
useGetLicenseTypeRequirementsQuery,
useCreateApplicationMutation,
@@ -1147,6 +1261,7 @@ export const {
useApproveDocumentsMutation,
useFinalApproveMutation,
useRejectApplicationMutation,
useGetEligibleExamsQuery,
useScheduleExamMutation,
useRecordExamOutcomeMutation,
useRetakeExamMutation,