jws-frontend/src/pages/09_task-order/TaskStatusComponent.vue
Aif 79d6482caa
Some checks failed
Spell Check / Spell Check with Typos (push) Failing after 6s
Add unique id and for attributes to status elements
Introduces dynamic id and for attributes to readonly status, dropdown, menu items, and failed remark button for improved accessibility and testability in TaskStatusComponent.vue.
2025-11-11 15:02:36 +07:00

207 lines
5.9 KiB
Vue

<script lang="ts" setup>
import { TaskStatus } from 'src/stores/task-order/types';
import { taskStatusReceiveToggle, taskStatusOrderToggle } from './constants';
import { computed } from 'vue';
const props = defineProps<{
readonly?: boolean;
noAction?: boolean;
type?: 'order' | 'receive';
status: string | TaskStatus | undefined;
}>();
defineEmits<{
(e: 'changeStatus', status: TaskStatus): void;
(e: 'clickFailed'): void;
}>();
const statusList = [
...taskStatusReceiveToggle,
...taskStatusOrderToggle,
{
value: TaskStatus.Validate,
icon: 'mdi-file-check-outline',
color: 'positive',
},
{
value: TaskStatus.Canceled,
icon: 'mdi-file-remove-outline',
color: 'negative',
},
];
const currStatus = computed(() =>
statusList.find((v) => v.value === props.status),
);
function inactiveCheck() {
if (props.type === 'order') {
return (
currStatus.value?.value === TaskStatus.InProgress ||
currStatus.value?.value === TaskStatus.Redo ||
currStatus.value?.value === TaskStatus.Success ||
currStatus.value?.value === TaskStatus.Complete ||
currStatus.value?.value === TaskStatus.Canceled ||
currStatus.value?.value === TaskStatus.Restart
);
}
if (props.type === 'receive') {
return (
currStatus.value?.value === TaskStatus.Failed ||
currStatus.value?.value === TaskStatus.Success ||
currStatus.value?.value === TaskStatus.Complete ||
currStatus.value?.value === TaskStatus.Redo ||
currStatus.value?.value === TaskStatus.Validate ||
currStatus.value?.value === TaskStatus.Canceled
);
}
}
</script>
<template>
<div
:id="`readonly-status-${status}`"
:for="`readonly-status-${status}`"
v-if="readonly"
class="row rounded bordered surface-2 items-center justify-center q-pa-xs no-wrap"
:style="`color: hsl(var(--${currStatus?.color}-bg))`"
>
<q-icon
:id="`readonly-status-icon-${status}`"
:name="currStatus?.icon"
class="q-pr-xs"
size="xs"
/>
<span :id="`readonly-status-label-${status}`">{{ $t(`taskOrder.status.${status}`) }}</span>
</div>
<div v-else class="row items-center justify-center no-wrap">
<q-btn-dropdown
:id="`btn-dropdown-status-${status}`"
:for="`btn-dropdown-status-${status}`"
dense
unelevated
:label="
currStatus?.value === TaskStatus.Validate && type === 'order'
? $t('taskOrder.done')
: currStatus?.value === TaskStatus.Redo && type === 'receive'
? $t(`taskOrder.status.receive.Canceled`)
: $t(`taskOrder.status.${status}`)
"
class="text-capitalize text-weight-regular product-status rounded"
:class="{
'inactive hide-icon q-pr-md': inactiveCheck(),
'hide-icon q-pr-md': noAction,
warning:
currStatus?.value === TaskStatus.Pending ||
currStatus?.value === TaskStatus.InProgress,
positive:
currStatus?.value === TaskStatus.Complete ||
currStatus?.value === TaskStatus.Success ||
currStatus?.value === TaskStatus.Validate,
negative:
currStatus?.value === TaskStatus.Failed ||
currStatus?.value === TaskStatus.Redo ||
currStatus?.value === TaskStatus.Canceled ||
currStatus?.value === TaskStatus.Restart,
'pointer-events-none': {
order: !['Success', 'Failed', 'Validate', 'Redo'].includes(
status || '',
),
receive: status !== TaskStatus.InProgress,
}[type ?? 'order'],
}"
:menu-offset="[0, 8]"
dropdown-icon="mdi-chevron-down"
content-class="bordered rounded"
@click.stop
:icon="currStatus?.icon"
>
<q-list v-if="!noAction" dense>
<q-item
:for="`menu-item-status-${v.value}`"
:id="`menu-item-status-${v.value}`"
v-for="(v, index) in type === 'order'
? {
Success: taskStatusOrderToggle.filter(
(v) => v.value === TaskStatus.Complete,
),
Failed: taskStatusOrderToggle.filter(
(v) =>
v.value === TaskStatus.Redo ||
v.value === TaskStatus.Restart,
),
Validate: taskStatusOrderToggle.filter(
(v) => v.value !== TaskStatus.InProgress,
),
}[status ?? '']
: {
InProgress: taskStatusReceiveToggle.filter((v) =>
[TaskStatus.Success, TaskStatus.Failed].includes(v.value),
),
}[status ?? '']"
:key="index"
clickable
v-close-popup
@click="$emit('changeStatus', v.value)"
class="items-center"
>
<q-icon
:style="`color: hsl(var(--${v.color}-bg))`"
:name="v.icon"
class="q-pr-sm"
size="xs"
></q-icon>
{{ $t(`taskOrder.status.${v.value}`) }}
</q-item>
</q-list>
</q-btn-dropdown>
<q-btn
:id="`btn-failed-remark-${status}`"
:for="`btn-failed-remark-${status}`"
v-if="currStatus?.value === TaskStatus.Failed"
flat
dense
rounded
color="negative"
icon="mdi-shield-alert-outline"
@click="$emit('clickFailed')"
/>
<div style="width: 31.94px" v-else></div>
</div>
</template>
<style scoped>
.product-status {
padding-left: 8px;
border-radius: 20px;
color: hsl(var(--_color));
background: hsla(var(--_color) / 0.15);
&.warning {
--_color: var(--warning-bg);
}
&.positive {
--_color: var(--positive-bg);
}
&.negative {
--_color: var(--negative-bg);
}
&.inactive {
--_color: var(--stone-7-hsl);
opacity: 0.8;
cursor: default;
}
}
.pointer-events-none {
pointer-events: none;
}
:deep(
.hide-icon
i.q-icon.mdi.mdi-chevron-down.q-btn-dropdown__arrow.q-btn-dropdown__arrow-container
) {
display: none;
}
</style>