Skip to content

Commit

Permalink
Implemented asset expiry.
Browse files Browse the repository at this point in the history
  • Loading branch information
mikeburg committed Nov 17, 2024
1 parent ed3e169 commit 6a06875
Show file tree
Hide file tree
Showing 5 changed files with 144 additions and 42 deletions.
11 changes: 11 additions & 0 deletions app/components/asset-checkout-form.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,17 @@
Show Asset History
</UiButton>
</div>
{{else if this.assetExpired}}
<ModalDialog @onEscape={{this.closeExpiredDialog}} as |Modal|>
<Modal.title>Asset Has Expired</Modal.title>
<Modal.body>
Asset {{this.assetExpired.barcode}} has expired and should not be handed out. Please place it
in the designated pile for return to the vendor.
</Modal.body>
<Modal.footer>
<UiCloseButton @onClick={{this.closeExpiredDialog}} />
</Modal.footer>
</ModalDialog>
{{else}}
<br>
{{/if}}
Expand Down
13 changes: 13 additions & 0 deletions app/components/asset-checkout-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export default class AssetCheckoutFormComponent extends Component {
@tracked isSubmitting = false;
@tracked showHistory = false;

@tracked assetExpired = null;

constructor() {
super(...arguments);

Expand All @@ -33,6 +35,7 @@ export default class AssetCheckoutFormComponent extends Component {
clearErrors() {
this.barcodeNotFound = false;
this.barcodeCheckedOut = null;
this.assetExpired = null;
}

/**
Expand Down Expand Up @@ -74,6 +77,8 @@ export default class AssetCheckoutFormComponent extends Component {
this.barcodeCheckedOut = result;
this.barcodeCheckedOut.barcode = barcode;
break;
case 'expired':
this.assetExpired = result;
}
} catch (response) {
this.house.handleErrorResponse(response)
Expand Down Expand Up @@ -116,4 +121,12 @@ export default class AssetCheckoutFormComponent extends Component {
this.modal.info('Asset not checked out', 'A barcode was entered, yet was not checked out. Either complete the check out process, or blank the barcode field before clicking on another tab.');
}

/**
* Close up the expired asset dialog
*/

@action
closeExpiredDialog() {
this.assetExpired = null;
}
}
52 changes: 51 additions & 1 deletion app/controllers/ops/assets.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,26 @@ import {
TYPE_VEHICLE
} from "clubhouse/models/asset";

const CSV_COLUMNS = [
{title: 'Barcode', key: 'barcode'},
{title: 'Type', key: 'type'},
{title: 'Description', key: 'description'},
{title: 'Assignment', key: 'assigned'},
{title: 'Category', key: 'category'},
{title: 'Notes', key: 'notes'},
{title: 'Year', key: 'year'},
{title: 'Expires On', key: 'expires_on', format: 'date'},
{title: 'Has Expired', key: 'has_expired'},
{title: 'Created At', key: 'created_at'},
];

export default class OpsAssetsController extends ClubhouseController {
queryParams = ['year'];

@tracked descriptionFilter = 'All';
@tracked typeFilter = 'All';
@tracked expireFilter = 'all';

@tracked assets;

@tracked assetForHistory;
Expand Down Expand Up @@ -79,6 +94,20 @@ export default class OpsAssetsController extends ClubhouseController {
}
}

switch (this.expireFilter) {
case 'all':
break;
case 'expired':
assets = assets.filter((asset) => asset.has_expired);
break;
case 'not-expired':
assets = assets.filter((asset) => !asset.has_expired);
break;
default:
assets = assets.filter((asset) => asset.expires_on === this.expireFilter);
break;
}

assets.sort((a, b) => a.barcode.localeCompare(b.barcode));

return assets;
Expand All @@ -96,12 +125,22 @@ export default class OpsAssetsController extends ClubhouseController {
}

get typeOptions() {
const options = _.uniqBy(this.assets, 'type').map((a) =>[a.typeLabel, a.type]);
const options = _.uniqBy(this.assets, 'type').map((a) => [a.typeLabel, a.type]);
options.sort((a, b) => a[0].localeCompare(b[0]));
options.unshift('All');
return options;
}

get expireFilterOptions() {
const options = _.sortBy(_.uniqBy(this.assets.filter((a) => a.expires_on !== null), 'expires_on'), 'expires_on')
.map((a) => [a.expires_on, a.expires_on]);

options.unshift(['Not Expired', 'not-expired']);
options.unshift(['Expired', 'expired']);
options.unshift(['All', 'all']);
return options;
}

@action
async assetHistoryAction(asset) {
this.assetForHistory = asset;
Expand Down Expand Up @@ -238,4 +277,15 @@ export default class OpsAssetsController extends ClubhouseController {
}
});
}

@action
exportToCSV() {
const assets = [...this.viewAssets];
assets.forEach((asset) => {
asset.assigned = asset.perm_assign ? 'Event' : 'Shift';
asset.has_expired = asset.has_expired ? 'Y' : '-';
});

this.house.downloadCsv(`${this.year}-assets-csv`, CSV_COLUMNS, assets);
}
}
3 changes: 3 additions & 0 deletions app/models/asset.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ export default class AssetModel extends Model {
@attr('number') year;
@attr('string', {readOnly: true}) created_at;

@attr('string') expires_on;
@attr('boolean', { readOnly: true}) has_expired;

get isRadio() {
return this.type === TYPE_RADIO;
}
Expand Down
107 changes: 66 additions & 41 deletions app/templates/ops/assets.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -5,67 +5,89 @@
@skipPandemic={{true}}
@onChange={{set-value this 'year'}} />
<FormRow>
<FormLabel @auto={{true}}>Type Filter</FormLabel>
<FormLabel @auto={{true}}>Type</FormLabel>
<div class="col-auto">
<ChForm::Select @name="typeFilter"
@value={{this.typeFilter}}
@options={{this.typeOptions}}
@onChange={{set-value this 'typeFilter'}}
/>
</div>
<FormLabel @auto={{true}}>Description Filter</FormLabel>
<FormLabel @auto={{true}}>Description</FormLabel>
<div class="col-auto">
<ChForm::Select @name="descriptionFilter"
@value={{this.descriptionFilter}}
@options={{this.descriptionOptions}}
@onChange={{set-value this 'descriptionFilter'}} />
</div>
<FormLabel @auto={{true}}>Expired?</FormLabel>
<div class="col-auto">
<ChForm::Select @name="expireFilter"
@value={{this.expireFilter}}
@options={{this.expireFilterOptions}}
@onChange={{set-value this 'expireFilter'}} />
</div>
<FormLabel @auto={{true}}>Action</FormLabel>
<div class="col-auto">
<UiButton @onClick={{this.newAsset}}>New Asset</UiButton>
</div>
</FormRow>

Showing {{this.viewAssets.length}} of {{pluralize this.assets.length "asset"}}
<UiTable>
<thead>
<tr>
<th>Barcode</th>
<th>Type</th>
<th>Description</th>
<th>Assigned</th>
<th>Actions</th>
</tr>
</thead>

<tbody>
{{#each this.viewAssets key="id" as |asset|}}
<tr>
<td>{{asset.barcode}}</td>
<td>{{asset.typeLabel}}</td>
<td>
<PresentOrNot @value={{asset.description}} @empty="-"/>
</td>
<td class="text-center">{{asset.assignmentLabel}}</td>
<td>
<UiButton @type="secondary" @size="sm" @onClick={{fn this.assetHistoryAction asset}}>
{{fa-icon "rectangle-list" right=1}} History
</UiButton>
<UiButton @size="sm" @onClick={{fn this.editAsset asset}}>
{{fa-icon "edit" right=1}} Edit
</UiButton>
</td>
</tr>
{{else if this.assets}}
<tr>
<td colspan="5" class="text-danger">No assets matched.</td>
</tr>
{{else}}
<td colspan="5" class="text-danger">No assets were found for {{this.year}}?!?</td>
{{/each}}
</tbody>
</UiTable>
<UiSection>
<:title> Showing {{this.viewAssets.length}} of {{pluralize this.assets.length "asset"}}</:title>
<:body>
<UiExportToCSVButton @onClick={{this.exportToCSV}} />
<UiTable>
<thead>
<tr>
<th>Barcode</th>
<th>Type</th>
<th>Description</th>
<th>Assigned</th>
<th>Expires On</th>
<th>Actions</th>
</tr>
</thead>

<tbody>
{{#each this.viewAssets key="id" as |asset|}}
<tr>
<td>{{asset.barcode}}</td>
<td>{{asset.typeLabel}}</td>
<td>
<PresentOrNot @value={{asset.description}} @empty="-"/>
</td>
<td class="text-center">{{asset.assignmentLabel}}</td>
<td>
{{#if asset.expires_on}}
{{ymd-format asset.expires_on}}
{{#if asset.has_expired}}
<UiBadge @type="warning" class="ms-1">expired</UiBadge>
{{/if}}
{{else}}
-
{{/if}}
</td>
<td>
<UiButton @type="secondary" @size="sm" @onClick={{fn this.assetHistoryAction asset}}>
{{fa-icon "rectangle-list" right=1}} History
</UiButton>
<UiButton @size="sm" @onClick={{fn this.editAsset asset}}>
{{fa-icon "edit" right=1}} Edit
</UiButton>
</td>
</tr>
{{else if this.assets}}
<tr>
<td colspan="5" class="text-danger">No assets matched.</td>
</tr>
{{else}}
<td colspan="5" class="text-danger">No assets were found for {{this.year}}?!?</td>
{{/each}}
</tbody>
</UiTable>
</:body>
</UiSection>
{{#if this.entry}}
<ModalDialog @title={{if this.entry.isNew "New Asset" "Edit Asset"}} @onEscape={{this.cancelAsset}} as |Modal|>
<ChForm @formId="asset"
Expand Down Expand Up @@ -108,6 +130,9 @@
@maxlength={{4}}
/>
</FormRow>
<FormRow>
<f.datetime @name="expires_on" @dateOnly={{true}} @label="Expires On (optional)"/>
</FormRow>
<FormRow>
<f.textarea @name="notes"
@label="Notes"
Expand Down

0 comments on commit 6a06875

Please sign in to comment.