Tuesday, 31 May 2022

Duplicate keys detected: 'X'. This may cause an update error. in VueJS datatable search

In my laravel vue application I have following datatable with some filters in a vue component(department-user-list.vue).

<template>
    <div>
        <cs-card
            :cardButton="false"
            :title="`Team members`"
        >
            <template slot="header-action">
                <div class="inline-block mr-4" direction-from="top">
                    <open-overlay identifier="corporateInviteEmployeeToDepartmentModal">
                        <cs-button size="small" variant="secondary">
                            Invite team member
                        </cs-button>
                    </open-overlay>
                </div>
                <div class="inline-block" direction-from="top">
                    <cs-button @click="redirectToAssignation" size="small">
                        Assign team member
                    </cs-button>
                </div>
            </template>
            <Datatable
                v-model="selectedForAction"
                :data="dataset"
                :headers="headers"
                :is-loading="isLoading"
                :has-action-bar-column="true"
                :key-id="`id`"
                :search-panel="{placeholder: 'Search team member...'}"
                @change="handlePaginationChange"
                @paginate="loadDepartmentEmployees"
            >
                <!--Filter Slot-->
                <template v-slot:filters>
                    <!--Nationality filter-->
                    <div class="w-2/12 pl-4 h-auto">
                        <cs-multiple-select
                            v-model="nationalitiesFilter"
                            :options="countries"
                            key-id="id"
                            label="name"
                            name="nationality"
                            placeholder="Nationality"
                        >
                        </cs-multiple-select>
                    </div>
                    <!--Certificate Status filter-->
                    <div class="w-6/12 pl-4 h-auto">
                        <cs-multiple-select
                            v-model="certificateStatusFilter"
                            :options="certificateStatus"
                            name="certificateStatusFilter"
                            placeholder="Qualification status"
                            @input="loadDepartmentEmployees"
                        />
                    </div>
                    <!--Matrix Status filter-->
                    <div class="w-4/12 pl-4 h-auto">
                        <cs-multiple-select
                            v-model="matrixStatusFilter"
                            :options="matrixStatus"
                            key-id="value"
                            label="label"
                            name="matrixStatusFilter"
                            placeholder="Matrix status"
                            @input="loadDepartmentEmployees"
                        />
                    </div>
                     <!--Employee Type  filter-->
                        <div class="w-4/12 pl-4 h-auto">
                            <cs-multiple-select
                                v-model="selectedEmployeeTypes"
                                :options="employeeType"
                                key-id="value"
                                label="label"
                                name="selectedEmployeeTypes"
                                placeholder="Employee type"
                                @input="loadDepartmentEmployees"
                            >
                            </cs-multiple-select>
                        </div>
                </template>

                <!--Table Header-->
                <template v-slot:header.country="{ header}">
                    <span class="material-icons-outlined">language</span>
                </template>

                <!--Table Body-->
                <template v-slot:item.name="{ item }">
                    <div class="flex items-center cursor-pointer">
                        <div class="rounded-full w-8 h-8 mr-4 overflow-hidden">
                            <img :src="item.profile_image[0].url" alt=""
                                 class="w-full h-full object-cover">
                        </div>
                        <a :href="employeeDetailRoute(item)">
                            <span class="text-certstyle-titles font-bold leading-loose"></span>
                        </a>
                        <span
                            v-if="item.is_subcontractor && item.company_name"
                            :title="item.company_name"
                            class="text-certstyle-text-light bg-certstyle-background flex font-semibold cursor-help  text-xs rounded mx-2 py-1 px-2"
                        >
                            
                             <span v-if="item.company_name.length > 10">...</span>
                        </span>
                    </div>
                </template>
                <template v-slot:item.job_title="{ item }">
                    
                </template>
                <template v-slot:item.country="{ item }">
                <span v-if="item.country" class="font-normal">
                    <country-flag width="w-5" :country-code="item.country.country_code"></country-flag>
                </span>
                </template>
                <template v-slot:item.certificate_status="{ item }">
                    <div class="status--summary--component inline-block mr-2 relative"
                         @click="getValidityStatus(item.certificate_matrix) !== 'all valid' &&
                            getValidityStatus(item.certificate_matrix) !== '-'
                             ? openCertificatesModal(item) : null
                         ">
                        <label :class="getValidityStatusClass(item.certificate_matrix)" class="badge">
                            
                        </label>
                    </div>
                </template>
                <template v-slot:item.matrix_status="{ item }">
                    <div class="status--summary--component inline-block mr-2 relative"
                         @click="getMatrixStatus(item.certificate_matrix) === 'non compliant'
                            ? openCertificatesModal(item)
                            : null
                         ">
                        <label :class="getMatrixStatusClass(item.certificate_matrix)" class="badge">
                            
                        </label>
                    </div>
                </template>
                <template v-slot:actionItems="slotProps">
                    <DatatableActionbarItem
                        :slot-props="slotProps"
                        identifier="removeConfirmationModal"
                        label="Remove"
                        variant="danger"
                    />
                </template>
                <template v-slot:rowActionItems="slotProps">
                    <DatatableActionbarItem
                        icon=""
                        label="Contact details"
                        @click.native="openContactDetailsModal(slotProps.item)"
                        :slot-props="slotProps"
                    />
                </template>
            </Datatable>


            <modal-md
                v-if="selectedEmployee !== null"
                :options="{ useDefaultContentStyling: false }"
                      :identifier="`statusSummaryComponent`">
                <template slot="modal_title">
                    Qualifications
                    <span v-if="selectedEmployee !== null && selectedEmployee !== undefined">
                            
                        </span>
                </template>


                <div class="bg-white" slot="modal_content">
                    <div
                        class="flex items-center justify-between text-certstyle-text-light bg-white border-certstyle-border border-b text-sm py-2 px-10">
                        <cs-dashboard-table-header-item-unstyled :item="`statusSummaryCertificateTitle`">
                            <p>Qualification</p>
                        </cs-dashboard-table-header-item-unstyled>

                        <cs-dashboard-table-header-item-unstyled :item="`statusSummaryCertificateStatus`">
                            <p>Validity Status</p>
                        </cs-dashboard-table-header-item-unstyled>

                        <cs-dashboard-table-header-item-unstyled :item="`statusSummaryMatrixStatus`">
                            <p>Matrix Status</p>
                        </cs-dashboard-table-header-item-unstyled>

                    </div>

                    <!--Certificates-->
                    <div class="text-certstyle-titles">
                        <div v-for="certificate in selectedEmployee.certificate_matrix"
                             v-if="selectedEmployee.certificate_matrix.length > 0"
                             class="table--row flex items-center justify-between border-certstyle-border last:border-b-0 border-b px-10 py-4">
                            <!-- Title -->
                            <cs-dashboard-table-item-unstyled
                                class="w-1/2"
                                :item="`statusSummaryCertificateTitle`">
                                <p :title="certificate.title" class=" ">
                                    
                                </p>
                            </cs-dashboard-table-item-unstyled>

                            <cs-dashboard-table-item-unstyled class="w-32" :item="`statusSummaryCertificateStatus`">
                                <div class="flex items-center justify-start w-full">
                                    <!--Expired styling-->
                                    <label v-if="certificate.matrix_status === 0"
                                           class="badge badge-danger">
                                        -
                                    </label>

                                    <!--Expires styling-->
                                    <label v-if="certificate.matrix_status &&  certificate.expired === 1"
                                           class="badge badge-danger">
                                        expired
                                    </label>
                                    <!--Expires styling-->
                                    <label v-if="certificate.matrix_status &&  certificate.expire_soon === 1"
                                           class="badge badge-danger">
                                        expires soon
                                    </label>

                                    <!--Active styling-->
                                    <label
                                        v-if="certificate.matrix_status &&  certificate.expire_soon === 0 && certificate.expired === 0"
                                        class="badge badge-success">
                                        active
                                    </label>
                                </div>
                            </cs-dashboard-table-item-unstyled>

                            <cs-dashboard-table-item-unstyled
                                class="w-32"
                                :item="`statusSummaryMatrixStatus`">
                                <!--Active styling-->
                                <label v-if="certificate.matrix_status"
                                       class="badge badge-success">
                                    compliant
                                </label>
                                <label v-else
                                       class="badge badge-danger">
                                    non-compliant
                                </label>
                            </cs-dashboard-table-item-unstyled>
                        </div>
                        <div v-else
                             class="table--row flex items-center justify-between border-certstyle-border last:border-b-0 border-b px-10 py-4">
                            <cs-dashboard-table-item-unstyled
                                class="w-1/2"
                                :item="`statusSummaryCertificateTitle`">
                                No certificates found
                            </cs-dashboard-table-item-unstyled>
                            <cs-dashboard-table-item-unstyled class="w-32"
                                                              :item="`statusSummaryCertificateStatus`">
                            </cs-dashboard-table-item-unstyled>
                            <cs-dashboard-table-item-unstyled
                                class="w-32"
                                :item="`statusSummaryMatrixStatus`">
                            </cs-dashboard-table-item-unstyled>
                        </div>
                    </div>
                </div>
            </modal-md>
        </cs-card>

        <contact-details
            v-if="userToShowContactDetails"
            :user="userToShowContactDetails"
        />

        <add-employee-modal
            :countries="countries"
            :identifier="`addEmployeeModal`"
            :invite-modal-title="`Invite to department`"
            :suggestion-url="userSuggestionApiURL"
            :title="`Assign to ${department ? department.name: ''}`"
            @inviteEmployees="handleInvitedEmployees"
            @selectEmployee="addEmployeeToDepartment"
            @removeEmployee="handleRemoveEmployee"
        />

        <cs-confirmation-modal
            v-if="checkRole(['admin', 'planner'])"
            @proceed="handleRemoveEmployee"
            identifier="removeConfirmationModal">
            <div class="text-certstyle-titles font-normal" slot="content">
                Removing employees from this department can not be undo.
            </div>

            <div slot="cancelButton"
                 class="cursor-pointer hover:bg-certstyle-background border border-certstyle-border rounded px-6 py-2 text-certstyle-text-light mr-4">
                Cancel
            </div>

            <cs-button slot="proceedButton">
                Remove
            </cs-button>
        </cs-confirmation-modal>
    </div>

</template>

This list and the filters works fine but when I try to search a user by typing their names, it kept giving me following error,

Duplicate keys detected: '1025'. This may cause an update error.

found in

---> at resources/js/components/reusable/datatable/Datatable.vue at resources/js/components/reusable/csCard.vue at resources/js/components/dashboard/communities/department/one-departments/department-user-list.vue

But when I try to filter the list by some other param, they get filtered without any error.

I'm struggling to find what I'm doing wrong here....

UPDATE

following is my non-filtered json data for a single user

 {
      "id": 1038,
      "unique_id": "0a3938c1-07d5-3884-9df0-a8fe3201a3e5",
      "first_name": "Mango",
      "last_name": "F1",
      "job_title": null,
      "email": "mangoF1@gmail.com",
      "phone_number": null,
      "phone_country_calling_code": null,
      "country_id": null,
      "company_name": null,
      "is_subcontractor": 0,
      "current_jobtitle": "Deck Foreman",
      "department_jobtitle": "Rigging Engineers",
      "language": "en",
      "email_verified_at": "2022-04-12T12:47:55.000000Z",
      "gender": null,
      "state": null,
      "postal_code": null,
      "house_number": null,
      "street": null,
      "city": null,
      "date_of_birth": null,
      "city_of_birth": null,
      "emergency_number": null,
      "opt_in": null,
      "created_at": "2022-04-12T12:46:34.000000Z",
      "updated_at": "2022-04-12T12:47:55.000000Z",
      "emergency_number_country_calling_code": null,
      "deleted_at": null,
      "has_ip_restriction": 0,
      "address": null,
      "latitude": null,
      "longitude": null,
      "place_id": null,
      "bouwpas_worker_id": null,
      "bouwpas_certificate_id": null,
      "certificate_matrix": [
        {
          "id": 463,
          .....
        }
      ]
    },

Following is my controller function,

public function index($locale, Company $company, Department $department, Request $request)
    {
        $this->authorize('viewUsers', [Department::class, $company, $department]);

        $users = $department->usersWithSubcontractors()
            //            ->notApiUser()
            ->select(
                'users.id',
                'unique_id',
                'first_name',
                'last_name',
                'job_title',
                'email',
                'phone_number',
                'unique_id',
                'phone_country_calling_code',
                'country_id',
                'company_name',
                'is_subcontractor',
            )->addSelect([
                'current_jobtitle' => JobTitle::selectRaw('IFNULL(project_specific_job_titles.title, job_titles.title)')
                    ->join('project_track_records', 'project_track_records.user_id', 'users.id', 'inner')
                    ->join('project_specific_job_titles', 'project_track_records.project_specific_job_title_id', 'project_specific_job_titles.id', 'inner')
                    ->whereColumn('job_titles.id', 'project_specific_job_titles.job_title_id')
                    ->whereDate('project_track_records.start_date', '<=', Carbon::now())
                    ->whereDate('project_track_records.end_date', '>=', Carbon::now())
                    ->limit(1),
                'department_jobtitle' => JobTitle::selectRaw('title')->whereColumn('job_titles.id', 'department_user.job_title_id'),
            ])->when(request('q'), function ($q) {
                $q->where(function ($q) {
                    $q->whereRaw("CONCAT_WS(' ', `first_name`, `last_name`) like '%" . request('q') . "%'");
                });
            })->when($request->get('employeeType'), function ($q) use ($request) {
                $q->whereIn('users.is_subcontractor', $request->get('employeeType'));
            })->paginate(\request('per_page', config('repository.pagination.limit')));

        $users->load('country');
        $users->append(['profile_image']);
        $users->makeVisible(['unique_id']);

        $users->map(fn ($item) => $item->certificate_matrix = (new GetCertificationMatrixQueryAction())->execute($item->id, $department->id));

        if ($request->filled('certificateStatus')) {
            $valid = in_array('valid', $request->get('certificateStatus'));
            $expire_soon = in_array('expire soon', $request->get('certificateStatus'));
            $expired = in_array('expired', $request->get('certificateStatus'));

            if ($valid) $users->setCollection($users->filter(fn ($item) => $item->certificate_matrix->filter(fn ($certificate) => $certificate->matrix_status && !$certificate->expire_soon && !$certificate->expired)->count() === $item->certificate_matrix->count())->values());
            if ($expire_soon && !$expired) $users->setCollection($users->filter(fn ($item) => $item->certificate_matrix->filter(fn ($certificate) => $certificate->matrix_status && $certificate->expire_soon)->count() > 0)->values());
            if ($expired && !$expire_soon) $users->setCollection($users->filter(fn ($item) => $item->certificate_matrix->filter(fn ($certificate) => $certificate->matrix_status && $certificate->expired)->count() > 0)->values());
        }

        if ($request->filled('matrixStatus')) {
            $compliant = in_array('compliant', $request->get('matrixStatus'));
            $non_compliant = in_array('non-compliant', $request->get('matrixStatus'));

            if ($non_compliant && !$compliant)
                $users->setCollection($users->filter(fn ($item) => $item->certificate_matrix->filter(fn ($certificate) => $certificate->matrix_status === 0 || $certificate->expire_soon || !$certificate->expired)->count() > 0)->values());

            if ($compliant && !$non_compliant)
                $users->setCollection($users->filter(fn ($item) => $item->certificate_matrix->filter(fn ($certificate) => $certificate->matrix_status && !$certificate->expire_soon && !$certificate->expired)->count() == $item->certificate_matrix->count())->values());
        }
        return response()->json($users);
    }


from Duplicate keys detected: 'X'. This may cause an update error. in VueJS datatable search

No comments:

Post a Comment