refactor: 03 Customer => improve responsive design across multiple components

This commit is contained in:
puriphatt 2025-01-27 13:47:33 +07:00
parent b8eec6f494
commit d012bb4d70
7 changed files with 106 additions and 33 deletions

View file

@ -343,7 +343,7 @@ const smallBanner = ref(false);
>
<template #error>
<div
class="full-width full-height flex items-center justify-center"
class="full-width full-height flex items-center justify-center no-padding"
:style="{
background: `${bgColor || 'var(--brand-1)'}`,
color: `${color || 'white'}`,

View file

@ -320,7 +320,7 @@ watchEffect(async () => {
<q-input
outlined
hide-bottom-space
class="col-3"
class="col-md-3 col-12"
v-model="homeCode"
mask="###########"
:dense="dense"
@ -344,7 +344,7 @@ watchEffect(async () => {
<q-input
outlined
hide-bottom-space
class="col"
class="col-md col-12"
:model-value="office"
:dense="dense"
:label="$t('customer.form.employmentOffice')"

View file

@ -2,7 +2,7 @@
import { ref, onMounted, watch } from 'vue';
import { storeToRefs } from 'pinia';
import { useI18n } from 'vue-i18n';
import { QTableProps } from 'quasar';
import { QSelect, QTableProps } from 'quasar';
import { useRoute } from 'vue-router';
import { baseUrl } from 'src/stores/utils';
@ -67,6 +67,7 @@ const currentCustomerUrlImage = defineModel<string | null>(
const { state: employeeFormState } = storeToRefs(employeeFormStore);
const refFilter = ref<InstanceType<typeof QSelect>>();
const currentStatus = ref<Status | 'All'>('All');
const currentBtnOpen = ref<boolean[]>([]);
const totalBranch = ref(0);
@ -334,11 +335,11 @@ watch(
</div>
</div>
<div class="row items-center justify-end col-12 col-md q-py-sm no-wrap">
<div class="row items-center justify-between col-12 col-md q-py-sm no-wrap">
<q-input
outlined
dense
class="col-6"
class="col-md-6 col"
:label="$t('general.search')"
:bg-color="$q.dark.isActive ? 'dark' : 'white'"
v-model="inputSearch"
@ -347,9 +348,25 @@ watch(
<template v-slot:prepend>
<q-icon name="mdi-magnify" />
</template>
<template v-if="$q.screen.lt.md" v-slot:append>
<span class="row">
<q-separator vertical />
<q-btn
icon="mdi-filter-variant"
unelevated
class="q-ml-sm"
padding="4px"
size="sm"
rounded
@click="refFilter?.showPopup"
/>
</span>
</template>
</q-input>
<q-select
v-show="$q.screen.gt.sm"
ref="refFilter"
id="select-status"
for="select-status"
v-model="currentStatus"
@ -657,7 +674,12 @@ watch(
totalEmployee: props.row._count?.employee,
}"
:visible-columns="branchFieldSelected"
@view-detail="$emit('viewDetail', props.row, props.rowIndex)"
@view-detail="
() => {
customerBranchFormStore.initForm('info', props.row.id);
customerBranchFormState.dialogModal = true;
}
"
/>
</div>
</template>
@ -868,7 +890,11 @@ watch(
v-model:wage-rate="customerBranchFormData.wageRate"
v-model:wage-rate-text="customerBranchFormData.wageRateText"
/>
<div class="row q-col-gutter-sm q-mb-sm" id="employer-branch-address">
<div
v-if="customerType === 'CORP'"
class="row q-col-gutter-sm q-mb-sm"
id="employer-branch-address"
>
<div class="col-12 text-weight-bold text-body1 row items-center">
<q-icon
flat
@ -882,6 +908,7 @@ watch(
</div>
</div>
<EmployerFormAuthorized
v-if="customerType === 'CORP'"
class="q-mb-xl"
prefix-id="employer-branch"
:readonly="customerBranchFormState.dialogType === 'info'"

View file

@ -1,7 +1,7 @@
<script setup lang="ts">
import { ref, watch, onMounted, computed } from 'vue';
import { useI18n } from 'vue-i18n';
import { useQuasar } from 'quasar';
import { QSelect, useQuasar } from 'quasar';
import { useRoute, useRouter } from 'vue-router';
import { getUserId, getRole } from 'src/services/keycloak';
import { baseUrl, waitAll } from 'src/stores/utils';
@ -101,6 +101,7 @@ const employeeFormStore = useEmployeeForm();
const optionStore = useOptionStore();
const ocrStore = useOcrStore();
const refFilter = ref<InstanceType<typeof QSelect>>();
const statusEmployeeCreate = ref<boolean>(false);
const mrz = ref<Awaited<ReturnType<typeof parseResultMRZ>>>();
const tabFieldRequired = ref<{ [key: string]: (keyof CustomerBranchCreate)[] }>(
@ -197,7 +198,7 @@ const customerNameInfo = computed(() => {
const currentBtnOpen = ref<boolean[]>([]);
const employeeStats = ref(0);
const gridView = ref(false);
const splitPercent = ref(15); // Customer only
const splitPercent = computed(() => ($q.screen.lt.md ? 0 : 15));
const currentPageCustomer = ref<number>(1);
const maxPageCustomer = ref<number>(1);
@ -906,7 +907,7 @@ const emptyCreateDialog = ref(false);
outlined
dense
:label="$t('general.search')"
class="col-12 col-md-3"
class="col col-md-3"
:bg-color="$q.dark.isActive ? 'dark' : 'white'"
v-model="inputSearch"
debounce="200"
@ -914,15 +915,26 @@ const emptyCreateDialog = ref(false);
<template #prepend>
<q-icon name="mdi-magnify" />
</template>
<template v-if="$q.screen.lt.md" v-slot:append>
<span class="row">
<q-separator vertical />
<q-btn
icon="mdi-filter-variant"
unelevated
class="q-ml-sm"
padding="4px"
size="sm"
rounded
@click="refFilter?.showPopup"
/>
</span>
</template>
</q-input>
<div
class="row col-md-5 col-12"
:class="{ 'q-pt-xs': $q.screen.lt.md }"
style="white-space: nowrap"
>
<!-- :class="{ 'offset-md-5': gridView }" -->
<div class="row col-md-5" style="white-space: nowrap">
<q-select
v-show="$q.screen.gt.sm"
ref="refFilter"
id="select-status"
for="select-status"
v-model="currentStatus"
@ -931,6 +943,7 @@ const emptyCreateDialog = ref(false);
autocomplete="off"
option-value="value"
option-label="label"
:class="{ 'offset-md-5': gridView }"
class="col"
map-options
emit-value
@ -943,6 +956,7 @@ const emptyCreateDialog = ref(false);
></q-select>
<!-- v-if="gridView === false" -->
<q-select
v-if="!gridView"
id="select-field"
for="select-field"
class="q-ml-sm col"
@ -1077,6 +1091,33 @@ const emptyCreateDialog = ref(false);
</q-tab>
</q-tabs>
</div>
<div
v-if="$q.screen.lt.md && currentTab === 'employer'"
class="q-px-md row q-gutter-x-sm items-center"
>
<nav
class="col rounded q-pa-sm text-center app-text-muted"
:class="{
'active-tab-sm': customerTypeSelected.value === v,
'bordered surface-1': customerTypeSelected.value !== v,
}"
v-for="v in fieldCustomer"
:key="v"
@click="customerTypeSelected = { label: v, value: v }"
id="`btn-sm-${v}`"
>
{{
$t(
{
all: 'general.all',
customerLegalEntity: 'customer.employerLegalEntity',
customerNaturalPerson: 'customer.employerNaturalPerson',
}[v],
)
}}
</nav>
</div>
</div>
<!-- body -->
@ -1087,6 +1128,7 @@ const emptyCreateDialog = ref(false);
class="col full-width"
before-class="overflow-hidden"
after-class="overflow-hidden"
:disable="$q.screen.lt.sm"
>
<template v-slot:before>
<div
@ -2096,7 +2138,7 @@ const emptyCreateDialog = ref(false);
class="col-12 col-md-10"
:class="{
'q-py-md q-pr-md ': $q.screen.gt.sm,
'q-py-md q-px-lg': !$q.screen.gt.sm,
'q-pa-sm': !$q.screen.gt.sm,
}"
id="customer-form-content"
style="height: 100%; max-height: 100%; overflow-y: auto"
@ -3922,7 +3964,7 @@ const emptyCreateDialog = ref(false);
'q-px-md q-pb-sm': !$q.screen.gt.sm,
}"
>
<div class="col bg-red surface-1 rounded bordered row">
<div class="col full-width surface-1 rounded bordered row">
<div class="col full-height scroll" v-if="$q.screen.gt.sm">
<div class="q-py-md q-pl-md q-pr-sm">
<SideMenu
@ -3981,7 +4023,7 @@ const emptyCreateDialog = ref(false);
class="col-12 col-md-10"
:class="{
'q-py-md q-pr-md ': $q.screen.gt.sm,
'q-py-md q-px-lg': !$q.screen.gt.sm,
'q-pa-sm': !$q.screen.gt.sm,
}"
id="customer-form-content"
style="height: 100%; max-height: 100%; overflow-y: auto"
@ -5721,4 +5763,9 @@ const emptyCreateDialog = ref(false);
transform: rotate(90deg);
transition: transform 0.3s ease;
}
.active-tab-sm {
color: hsla(var(--info-bg) / 1);
background-color: hsla(var(--info-bg) / 0.1);
}
</style>

View file

@ -167,7 +167,7 @@ watch(
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md-5"
class="col-12 col-md-5"
:label="$t('customer.form.employerName')"
for="input-legal-person-no"
:model-value="customerName"
@ -224,7 +224,7 @@ watch(
<div class="col-12 row q-col-gutter-sm">
<DatePicker
v-model="registerDate"
class="col-6 col-md-2"
class="col-12 col-md-2"
:id="`${prefixId}-input-register-date`"
:label="$t('customer.form.registerDate')"
:readonly="readonly"
@ -264,7 +264,7 @@ watch(
outlined
:readonly="readonly"
hide-bottom-space
class="col-6 col-md-3"
class="col-12 col-md-3"
:label="$t('customer.form.headQuarters.telephoneNo')"
for="input-telephone-no"
:model-value="readonly ? telephoneNo || '-' : telephoneNo"
@ -285,7 +285,7 @@ watch(
</template>
<template v-if="customerType === 'PERS'">
<div class="col-7 row q-col-gutter-sm">
<div class="col-md-7 col-12 row q-col-gutter-sm">
<q-input
dense
outlined
@ -320,7 +320,7 @@ watch(
/>
</div>
<div class="col-9 row q-col-gutter-sm">
<div class="col-md-9 col-12 row q-col-gutter-sm">
<q-select
outlined
use-input
@ -360,7 +360,7 @@ watch(
outlined
:readonly="readonly"
hide-bottom-space
class="col"
class="col-md col-12"
:label="$t('personnel.form.firstName')"
:model-value="firstName"
@update:model-value="
@ -384,7 +384,7 @@ watch(
/>
</div>
<div class="col-9 row q-col-gutter-sm">
<div class="col-md-9 col-12 row q-col-gutter-sm">
<q-input
:for="`${prefixId}-input-prefix-name`"
dense
@ -411,7 +411,7 @@ watch(
outlined
:readonly="readonly"
hide-bottom-space
class="col"
class="col-md col-12"
label="Name"
:model-value="firstNameEN"
@update:model-value="
@ -443,13 +443,13 @@ watch(
/>
</div>
<div class="row col-9 q-col-gutter-sm">
<div class="row col-md-9 col-12 q-col-gutter-sm">
<q-input
:for="`${prefixId}-input-telephone`"
dense
outlined
:readonly="readonly"
class="col-md col-6"
class="col-md col-12"
:label="$t('form.telephone')"
:mask="readonly ? '' : '##########'"
:model-value="readonly ? telephoneNo || '-' : telephoneNo"

View file

@ -96,7 +96,7 @@ const telephoneNo = defineModel<string>('telephoneNo', { default: '' });
</div>
<div class="col-12 row q-col-gutter-sm">
<div class="col-12 row q-col-gutter-sm">
<div class="col-md-5 col-12">
<SelectBranch
:for="`${prefixId}-input-source-registered-branch`"
class="col-md-6"

View file

@ -25,8 +25,6 @@ import {
} from 'components/button';
import { UploadFileGroup } from 'src/components/upload-file/';
import { uploadFileListCustomer, columnsAttachment } from '../../constant';
import { symOutlinedResume } from '@quasar/extras/material-symbols-outlined';
import { group } from 'console';
const ocrStore = useOcrStore();
const customerStore = useCustomerStore();
@ -114,6 +112,7 @@ withDefaults(
class="bordered-b"
active-color="primary"
no-caps
mobile-arrows
style="color: hsl(var(--text-mute))"
>
<q-tab name="main" :label="$t('customerBranch.tab.main')" />