Skip to content

Commit

Permalink
fetch intended use choices from api & query with leases service_unit (#…
Browse files Browse the repository at this point in the history
…489)

this change filters intended use choices based on service_unit
adds and improves typing here and there
  • Loading branch information
henrinie-nc committed Jun 13, 2024
1 parent 547f4f3 commit b96077c
Show file tree
Hide file tree
Showing 17 changed files with 113 additions and 22 deletions.
6 changes: 4 additions & 2 deletions src/api/callApiAsync.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { store } from "root/startApp";
import { getApiToken } from "auth/selectors";
import { UI_ACCEPT_LANGUAGE_VALUE } from "api/constants";
import type { ApiSyncResponse } from "./types";
import type { ApiResponse } from "types";

const callApiAsync = async (request: Request): Promise<Record<string, any>> => {
const apiToken = await getApiToken(store.getState());
const callApiAsync = async <T = ApiResponse>(request: Request): Promise<ApiSyncResponse<T>> => {
const apiToken = getApiToken(store.getState());

if (apiToken) {
request.headers.set('Authorization', `Bearer ${apiToken}`);
Expand Down
4 changes: 4 additions & 0 deletions src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,8 @@ export type ReceiveErrorAction = Action<string, ApiError>;
export type ClearErrorAction = Action<string, void>;
export type ApiState = {
error: ApiError;
};
export type ApiSyncResponse<T> = {
response: Response,
bodyAsJson: T
};
4 changes: 2 additions & 2 deletions src/areaSearch/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ export const getIsFetchingAttributes: Selector<boolean, void> = (state: RootStat
export const getListAttributes: Selector<Attributes, void> = (state: RootState): Attributes => state.areaSearch.listAttributes;
export const getListMethods: Selector<Methods, void> = (state: RootState): Methods => state.areaSearch.listMethods;
export const getIsFetchingListAttributes: Selector<boolean, void> = (state: RootState): boolean => state.areaSearch.isFetchingListAttributes;
export const getAreaSearchList: Selector<ApiResponse, void> = (state: RootState): ApiResponse => state.areaSearch.areaSearchList;
export const getAreaSearchListByBBox: Selector<ApiResponse, void> = (state: RootState): ApiResponse => state.areaSearch.areaSearchListByBBox;
export const getAreaSearchList: Selector<ApiResponse, void> = <T>(state: RootState): ApiResponse<T> => state.areaSearch.areaSearchList;
export const getAreaSearchListByBBox: Selector<ApiResponse, void> = <T>(state: RootState): ApiResponse<T> => state.areaSearch.areaSearchListByBBox;
export const getIsFetchingAreaSearchList: Selector<boolean, void> = (state: RootState): boolean => state.areaSearch.isFetchingAreaSearchList;
export const getIsFetchingAreaSearchListByBBox: Selector<boolean, void> = (state: RootState): boolean => state.areaSearch.isFetchingAreaSearchListByBBox;
export const getCurrentAreaSearch: Selector<Record<string, any>, void> = (state: RootState): Record<string, any> => state.areaSearch.currentAreaSearch;
Expand Down
2 changes: 1 addition & 1 deletion src/batchrun/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const getIsFetchingJobRunLogEntryAttributes: Selector<boolean, void> = (s
export const getJobRunLogEntryAttributes: Selector<Attributes, void> = (state: RootState): Attributes => state.batchrun.jobRunLogEntryAttributes;
export const getJobRunLogEntryMethods: Selector<Methods, void> = (state: RootState): Methods => state.batchrun.jobRunLogEntryMethods;
export const getIsFetchingJobRunLogEntriesByRun: Selector<boolean, number> = (state: RootState, run: number): boolean => state.batchrun.isFetchingJobRunLogEntriesByRun[run];
export const getJobRunLogEntriesByRun: Selector<ApiResponse, number> = (state: RootState, run: number): ApiResponse => state.batchrun.jobRunLogEntriesByRun[run];
export const getJobRunLogEntriesByRun: Selector<ApiResponse, number> = <T>(state: RootState, run: number): ApiResponse<T> => state.batchrun.jobRunLogEntriesByRun[run];
export const getIsFetchingScheduledJobAttributes: Selector<boolean, void> = (state: RootState): boolean => state.batchrun.isFetchingScheduledJobAttributes;
export const getScheduledJobAttributes: Selector<Attributes, void> = (state: RootState): Attributes => state.batchrun.scheduledJobAttributes;
export const getScheduledJobMethods: Selector<Methods, void> = (state: RootState): Methods => state.batchrun.scheduledJobMethods;
Expand Down
37 changes: 37 additions & 0 deletions src/components/form/FieldTypeIntendedUseSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from "react";
import debounce from "lodash/debounce";
import AsyncSelect from "components/form/AsyncSelect";
import { addEmptyOption, sortStringByKeyAsc } from "util/helpers";
import { getContentIntendedUse } from "leases/helpers";
import { fetchIntendedUses } from "leases/requestsAsync";
import type { ServiceUnit } from "serviceUnits/types";
type Props = {
disabled?: boolean;
displayError: boolean;
input: Record<string, any>;
isDirty: boolean;
onChange: (...args: Array<any>) => any;
placeholder?: string;
serviceUnit: ServiceUnit;
};
const FieldTypeIntendedUseSelect = ({
disabled,
displayError,
input,
isDirty,
onChange,
placeholder,
serviceUnit
}: Props): React.ReactNode => {
const getIntendedUses = debounce(async (inputValue: string, callback: (...args: Array<any>) => any) => {
const intendedUses = await fetchIntendedUses({
search: inputValue,
limit: 20,
service_unit: serviceUnit?.id || ""
});
callback(addEmptyOption(intendedUses.map((intendedUse) => getContentIntendedUse(intendedUse)).sort((a, b) => sortStringByKeyAsc(a, b, 'label'))));
}, 500);
return <AsyncSelect disabled={disabled} displayError={displayError} getOptions={getIntendedUses} input={input} isDirty={isDirty} onChange={onChange} placeholder={placeholder} />;
};

export default FieldTypeIntendedUseSelect;
5 changes: 5 additions & 0 deletions src/components/form/FormField.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import FieldTypeCheckboxDateTime from "components/form/FieldTypeCheckboxDateTime
import FieldTypeContactSelect from "components/form/FieldTypeContactSelect";
import FieldTypeDatePicker from "components/form/FieldTypeDatePicker";
import FieldTypeDecimal from "components/form/FieldTypeDecimal";
import FieldTypeIntendedUseSelect from "components/form/FieldTypeIntendedUseSelect";
import FieldTypeLeaseSelect from "components/form/FieldTypeLeaseSelect";
import FieldTypeLessorSelect from "components/form/FieldTypeLessorSelect";
import FieldTypeMultiSelect from "components/form/FieldTypeMultiSelect";
Expand Down Expand Up @@ -47,6 +48,7 @@ const FieldTypes = {
[FieldTypeOptions.DECIMAL]: FieldTypeDecimal,
[FieldTypeOptions.FIELD]: FieldTypeSelect,
[FieldTypeOptions.INTEGER]: FieldTypeBasic,
[FieldTypeOptions.INTENDED_USE]: FieldTypeIntendedUseSelect,
[FieldTypeOptions.LEASE]: FieldTypeLeaseSelect,
[FieldTypeOptions.LESSOR]: FieldTypeLessorSelect,
[FieldTypeOptions.MULTISELECT]: FieldTypeMultiSelect,
Expand Down Expand Up @@ -187,6 +189,9 @@ const FormFieldInput = ({
case FieldTypeOptions.USER:
return getUserFullName(value);

case FieldTypeOptions.INTENDED_USE:
return value ? value.label : '-';

default:
console.error(`Field type ${type} is not implemented`);
return 'NOT IMPLEMENTED';
Expand Down
5 changes: 3 additions & 2 deletions src/contacts/requestsAsync.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import createUrl from "api/createUrl";
import callApiAsync from "api/callApiAsync";
import { ContactExistsResponse } from "./types";
export const fetchContacts = async (query?: Record<string, any>) => {
const {
response: {
Expand All @@ -17,13 +18,13 @@ export const fetchContacts = async (query?: Record<string, any>) => {
return [];
}
};
export const contactExists = async (identifier: string) => {
export const contactExists = async (identifier: string): Promise<boolean | Array<any>> => {
const {
response: {
status
},
bodyAsJson
} = await callApiAsync(new Request(createUrl(`contact_exists/?identifier=${identifier}`)));
} = await callApiAsync<ContactExistsResponse>(new Request(createUrl(`contact_exists/?identifier=${identifier}`)));

switch (status) {
case 200:
Expand Down
3 changes: 3 additions & 0 deletions src/contacts/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ export type ContactState = {
list: ContactList;
methods: Methods;
};
export type ContactExistsResponse = {
exists: boolean;
}
export type Contact = Record<string, any>;
export type ContactId = number;
export type ContactList = any;
Expand Down
1 change: 1 addition & 0 deletions src/enums.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ export const FieldTypes = {
DECIMAL: 'decimal',
FIELD: 'field',
INTEGER: 'integer',
INTENDED_USE: 'intended_use',
LEASE: 'lease',
LESSOR: 'lessor',
MULTISELECT: 'multiselect',
Expand Down
6 changes: 1 addition & 5 deletions src/leases/components/leaseSections/summary/Summary.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ type State = {
currentLease: Lease;
financingOptions: Array<Record<string, any>>;
hitasOptions: Array<Record<string, any>>;
intendedUseOptions: Array<Record<string, any>>;
managementOptions: Array<Record<string, any>>;
noticePeriodOptions: Array<Record<string, any>>;
regulationOptions: Array<Record<string, any>>;
Expand All @@ -64,7 +63,6 @@ class Summary extends PureComponent<Props, State> {
currentLease: {},
financingOptions: [],
hitasOptions: [],
intendedUseOptions: [],
lessorOptions: [],
managementOptions: [],
noticePeriodOptions: [],
Expand All @@ -86,7 +84,6 @@ class Summary extends PureComponent<Props, State> {
newState.classificationOptions = getFieldOptions(props.attributes, LeaseFieldPaths.CLASSIFICATION);
newState.financingOptions = getFieldOptions(props.attributes, LeaseFieldPaths.FINANCING);
newState.hitasOptions = getFieldOptions(props.attributes, LeaseFieldPaths.HITAS);
newState.intendedUseOptions = getFieldOptions(props.attributes, LeaseFieldPaths.INTENDED_USE);
newState.managementOptions = getFieldOptions(props.attributes, LeaseFieldPaths.MANAGEMENT);
newState.noticePeriodOptions = getFieldOptions(props.attributes, LeaseFieldPaths.NOTICE_PERIOD);
newState.regulationOptions = getFieldOptions(props.attributes, LeaseFieldPaths.REGULATION);
Expand Down Expand Up @@ -140,7 +137,6 @@ class Summary extends PureComponent<Props, State> {
classificationOptions,
financingOptions,
hitasOptions,
intendedUseOptions,
managementOptions,
noticePeriodOptions,
regulationOptions,
Expand Down Expand Up @@ -239,7 +235,7 @@ class Summary extends PureComponent<Props, State> {
<FormTextTitle uiDataKey={getUiDataLeaseKey(LeaseFieldPaths.INTENDED_USE)}>
{LeaseFieldTitles.INTENDED_USE}
</FormTextTitle>
<FormText>{getLabelOfOption(intendedUseOptions, summary.intended_use) || '-'}</FormText>
<FormText>{(summary.intended_use && summary.intended_use.name) || '-'}</FormText>
</Authorization>
</Column>
<Column small={12} medium={6} large={8}>
Expand Down
3 changes: 2 additions & 1 deletion src/leases/components/leaseSections/summary/SummaryEdit.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,9 @@ class SummaryEdit extends PureComponent<Props, State> {
<Column small={12} medium={6} large={4}>
<Authorization allow={isFieldAllowedToRead(attributes, LeaseFieldPaths.INTENDED_USE)}>
<FormField disableTouched={isSaveClicked} fieldAttributes={getFieldAttributes(attributes, LeaseFieldPaths.INTENDED_USE)} name='intended_use' overrideValues={{
fieldType: FieldTypes.INTENDED_USE,
label: LeaseFieldTitles.INTENDED_USE
}} enableUiDataEdit uiDataKey={getUiDataLeaseKey(LeaseFieldPaths.INTENDED_USE)} />
}} serviceUnit={currentLease.service_unit} enableUiDataEdit uiDataKey={getUiDataLeaseKey(LeaseFieldPaths.INTENDED_USE)} />
</Authorization>
</Column>
<Column small={12} medium={6} large={8}>
Expand Down
23 changes: 20 additions & 3 deletions src/leases/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { addEmptyOption, convertStrToDecimalNumber, fixedLengthNumber, formatDat
import { getCoordinatesOfGeometry } from "util/map";
import { getIsEditMode } from "./selectors";
import { removeSessionStorageItem } from "util/storage";
import type { Lease } from "./types";
import type { Lease, IntendedUse } from "./types";
import type { CommentList } from "comments/types";
import type { Attributes, LeafletFeature, LeafletGeoJson } from "types";
import type { RootState } from "root/types";
Expand Down Expand Up @@ -212,6 +212,23 @@ export const getContentLeaseInfo = (lease: Record<string, any>): Record<string,
};
};

/**
* Get contenr for intended use
* @param {Object} intendedUse
* @returns {Object}
*/
export const getContentIntendedUse = (intendedUse: IntendedUse): Record<string, any> | null => {
if (!intendedUse) return null;
return {
id: intendedUse.id,
value: intendedUse.id,
label: intendedUse.name,
name: intendedUse.name,
service_unit: intendedUse.service_unit,
};
}


/**
* Get content lease address
* @param {Object} lease
Expand Down Expand Up @@ -269,7 +286,7 @@ export const getContentLeaseSummary = (lease: Record<string, any>): Record<strin
financing: lease.financing,
hitas: lease.hitas,
infill_development_compensations: getContentLeaseInfillDevelopmentCompensations(lease),
intended_use: lease.intended_use,
intended_use: getContentIntendedUse(lease.intended_use),
intended_use_note: lease.intended_use_note,
internal_order: lease.internal_order,
is_subject_to_vat: lease.is_subject_to_vat,
Expand Down Expand Up @@ -1974,7 +1991,7 @@ export const addSummaryFormValuesToPayload = (payload: Record<string, any>, form
end_date: formValues.end_date,
financing: formValues.financing,
hitas: formValues.hitas,
intended_use: formValues.intended_use,
intended_use: get(formValues, 'intended_use.value'),
intended_use_note: formValues.intended_use_note,
internal_order: formValues.internal_order,
is_subject_to_vat: formValues.is_subject_to_vat,
Expand Down
18 changes: 18 additions & 0 deletions src/leases/requestsAsync.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import createUrl from "api/createUrl";
import callApiAsync from "api/callApiAsync";
import type { IntendedUse } from "./types";
export const fetchLeases = async (query?: Record<string, any>) => {
const {
response: {
Expand Down Expand Up @@ -84,4 +85,21 @@ export const fetchDecisions = async (query?: Record<string, any>) => {
console.error('Failed to fetch decisions');
return [];
}
};
export const fetchIntendedUses = async (query?: Record<string, any>): Promise<Array<IntendedUse>> => {
const {
response: {
status
},
bodyAsJson
} = await callApiAsync(new Request(createUrl('intended_use/', query)));

switch (status) {
case 200:
return bodyAsJson.results;

default:
console.error('Failed to fetch intended uses');
return [];
}
};
6 changes: 6 additions & 0 deletions src/leases/types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Action, ApiResponse, Attributes, Methods } from "../types";
import type { ServiceUnit } from "serviceUnits/types";
export type LeaseState = {
attributes: Attributes;
byId: Record<string, any>;
Expand Down Expand Up @@ -37,6 +38,11 @@ export type SendEmailPayload = {
recipients: Array<number>;
text: string;
};
export type IntendedUse = {
id: number;
name: string;
service_unit: ServiceUnit["id"];
};
export type FetchAttributesAction = Action<string, void>;
export type ReceiveAttributesAction = Action<string, Attributes>;
export type ReceiveMethodsAction = Action<string, Methods>;
Expand Down
2 changes: 1 addition & 1 deletion src/serviceUnits/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type { Action } from "../types";
export type ServiceUnit = Record<string, any>;
export type ServiceUnit = { id: number, name: string };
export type ServiceUnits = Array<Record<string, any>>;
export type ServiceUnitState = {
isFetching: boolean;
Expand Down
4 changes: 2 additions & 2 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ export type Selector<Value, Props> = (state: RootState, props: Props) => Value;
export type Attributes = Record<string, any> | null | undefined;
export type Reports = Record<string, any> | null | undefined;
export type Methods = Record<string, any> | null | undefined;
export type ApiResponse = ({
export type ApiResponse<T = any> = ({
count: number;
next: string | null | undefined;
previous: string | null | undefined;
results: Array<Record<string, any>>;
results: Array<T>;
} | null | undefined) | null;
type Coordinate = Array<number>;
export type LeafletFeatureGeometry = {
Expand Down
6 changes: 3 additions & 3 deletions src/util/helpers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -651,15 +651,15 @@ export const createPTPPlotDivisionUrl = (plotDivisionId: string): string => `${P
* @param {Object} response
* @returns {number}
*/
export const getApiResponseCount = (response: ApiResponse): number => get(response, 'count', 0);
export const getApiResponseCount = <T,>(response: ApiResponse<T>): number => get(response, 'count', 0);

/**
* Get maximum number of pages from api response
* @param {Object} response
* @param {number} size
* @returns {number}
*/
export const getApiResponseMaxPage = (response: ApiResponse, size: number): number => {
export const getApiResponseMaxPage = <T,>(response: ApiResponse<T>, size: number): number => {
const count = getApiResponseCount(response);
return Math.ceil(count / size);
};
Expand All @@ -669,7 +669,7 @@ export const getApiResponseMaxPage = (response: ApiResponse, size: number): numb
* @param {Object} response
* @returns {Object[]}
*/
export const getApiResponseResults = (response: ApiResponse): Array<Record<string, any>> => get(response, 'results', []);
export const getApiResponseResults = <T,>(response: ApiResponse<T>): Array<Record<string, any>> => get(response, 'results', []);

/**
* Get React component by dom id
Expand Down

0 comments on commit b96077c

Please sign in to comment.