diff --git a/src/App.vue b/src/App.vue index f305469..6bf6837 100644 --- a/src/App.vue +++ b/src/App.vue @@ -63,24 +63,16 @@ function changeModel() { citizen.value = { id: '05954ccb-188b-4e56-bba8-53211d60e343', name: 'Dr. Monique Orn', - gender: 'F', + gender: null, cpf_responsible: null, mother_name: 'Jaime Powlowski DDS', cpf: '56826137918', cns: '440541140933040', - birth_date: '1946-10-02', + birth_date: null, phone: '38 4017-7733', cellphone: '83 7530-1849', email: 'joaopaulosncastro@sysvale.com.br', - address: { - cep: '44443', - street: 'Jakubowski Manors', - number: '625', - complement: 'Suite 152', - neighborhood: 'Shanahan Glen', - city: 'Albinborough', - uf: 'NY', - }, + address: null, race: 'black', co_cidadao: 2852, is_dead: true, diff --git a/src/components/CitizenSummaryViewer.test.ts b/src/components/CitizenSummaryViewer.test.ts index 315e781..b6c6f96 100644 --- a/src/components/CitizenSummaryViewer.test.ts +++ b/src/components/CitizenSummaryViewer.test.ts @@ -40,6 +40,11 @@ const femaleCitizen: Partial = { mother_name: 'Mary Doe', }; +const incompleteCitizen: Partial = { + ...maleCitizen, + mother_name: '', +}; + const stubs = { CdsText: true, CdsBadge: true, @@ -83,6 +88,8 @@ describe('CitizenSummaryViewer', () => { expect(wrapper.findComponent('[data-testid="pregnant-badge"]').exists()).toBeFalsy(); expect(pregnantCitizenWrapper.findComponent('[data-testid="pregnant-badge"]').exists()).toBeTruthy(); + + pregnantCitizenWrapper.unmount(); }); test('actions are hidden accordingly to props', async () => { @@ -128,4 +135,51 @@ describe('CitizenSummaryViewer', () => { closeButton.trigger('cds-click'); expect(wrapper.emitted('close')).toBeTruthy(); }); + + test('shows missing fields warning and amber variant when required fields are missing', async () => { + const incompleteCitizenWrapper = await mount(CitizenSummaryViewer, { + props: { + citizen: incompleteCitizen, + }, + global: { + plugins: [Cuida], + stubs: { + ...stubs, + CdsText: false, + }, + }, + }); + + const missingFieldsAlert = incompleteCitizenWrapper.find('[data-testid="missing-fields-alert"]'); + + expect(incompleteCitizenWrapper.vm.hasMissingFields).toBeTruthy(); + expect(incompleteCitizenWrapper.find('.box--amber').exists()).toBeTruthy(); + expect(missingFieldsAlert.exists()).toBeTruthy(); + expect(missingFieldsAlert.find('svg[aria-labelledby="warning-outline"]').exists()).toBeTruthy(); + expect(missingFieldsAlert.text()).toContain('Cadastro incompleto'); + + incompleteCitizenWrapper.unmount(); + }); + + test('should not show missing fields warning when hidden fields fields are missing', async () => { + const incompleteCitizenWrapper = await mount(CitizenSummaryViewer, { + props: { + citizen: incompleteCitizen, + hiddenFields: ['mother_name'], + }, + global: { + plugins: [Cuida], + stubs: { + ...stubs, + CdsText: false, + }, + }, + }); + + expect(incompleteCitizenWrapper.find('[data-testid="missing-fields-alert"]').exists()).toBeFalsy(); + expect(incompleteCitizenWrapper.vm.hasMissingFields).toBeFalsy(); + expect(incompleteCitizenWrapper.find('.box--amber').exists()).toBeFalsy(); + + incompleteCitizenWrapper.unmount(); + }); }); diff --git a/src/components/CitizenSummaryViewer.vue b/src/components/CitizenSummaryViewer.vue index 30fc282..44c8a96 100644 --- a/src/components/CitizenSummaryViewer.vue +++ b/src/components/CitizenSummaryViewer.vue @@ -2,7 +2,10 @@
- + @@ -52,11 +55,30 @@ + + + + Cadastro incompleto + + import { watch, ref, onMounted, toRef } from 'vue'; +import { isEmpty, isNil, isObject, isString } from 'lodash'; // @ts-ignore import { smartTitleCase } from '@sysvale/foundry'; import { Citizen as CitizenModel } from '@/models/Citizen'; @@ -118,16 +141,73 @@ const emits = defineEmits(['create', 'edit', 'close']); const internalCitizen = ref(); const emptyStateImage = emptyState; +const hasMissingFields = ref(false); -onMounted(() => fillCitizen(props.citizen)); +onMounted(() => { + checkMissingRequiredFields(props.citizen); + fillCitizen(props.citizen); +}); -watch(toRef(props, 'citizen'), (newValue) => fillCitizen(newValue)); +watch(toRef(props, 'citizen'), (newValue) => { + checkMissingRequiredFields(newValue); + fillCitizen(newValue); +}); function fillCitizen(citizenInfo: any | null) { if (!citizenInfo) return; internalCitizen.value = new CitizenModel(citizenInfo); } + +function checkMissingRequiredFields(value: Partial | null) { + if (!value) { + hasMissingFields.value = false; + return; + } + + const citizen = value as Record; + const genderValue = citizen['gender'] ?? citizen['_gender']; + const addressValue = citizen['address'] ?? citizen['_address']; + const addressSource = (addressValue as Record) ?? { + street: citizen['street'], + number: citizen['number'], + neighborhood: citizen['neighborhood'], + city: citizen['city'], + uf: citizen['uf'], + }; + + const missingCpfAndCnsFields = ['cpf', 'cns'].some( + field => isEmptyValue(citizen[field]) && !props.hiddenFields.includes(field) + ); + + const missingCitizenFields = ['name', 'birth_date', 'mother_name', 'race'].some( + field => isEmptyValue(citizen[field]) && !props.hiddenFields.includes(field) + ) || isEmptyValue(genderValue); + + const missingAddressFields = ['street', 'number', 'neighborhood', 'city', 'uf'].some( + field => isEmptyValue(addressSource?.[field]) && !props.hiddenFields.includes(field) + ); + + hasMissingFields.value = missingCitizenFields || missingAddressFields || missingCpfAndCnsFields; +} + +function isEmptyValue(value: unknown) { + if (isNil(value)) return true; + if (isString(value)) return value.trim() === ''; + if (!isObject(value)) return false; + + const obj = value as Record; + if ('value' in obj) return isEmptyValue(obj.value); + if ('name' in obj) return isEmptyValue(obj.name); + if ('shortName' in obj) return isEmptyValue(obj.shortName); + if ('id' in obj) return isEmptyValue(obj.id); + + return isEmpty(obj); +} + +defineExpose({ + hasMissingFields, +})