chore: initial import for test contour
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import axios from 'axios';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { apiUrl } from '@/config/api';
|
||||
|
||||
import { useGetFilialsQuery } from '../api/apiFilial';
|
||||
import { useGetDepartmentsQuery } from '../api/apiDepartment';
|
||||
import { selectRegions } from '../store/slice/regionSlice';
|
||||
import { useGetEmptyLocationsQuery } from '../api/apiLocation';
|
||||
|
||||
export function useLostDoctors() {
|
||||
const { data, isLoading, error } = useGetEmptyLocationsQuery();
|
||||
|
||||
const [ lostDoctors, setLostDoctors ] = useState([]);
|
||||
|
||||
const filialsQuery = useGetFilialsQuery();
|
||||
const filials = filialsQuery.data ?? [];
|
||||
|
||||
const departmentsQuery = useGetDepartmentsQuery();
|
||||
const departments = departmentsQuery.data ?? [];
|
||||
const regions = useSelector(selectRegions);
|
||||
|
||||
const fetchParams = [ 'filial', 'dcode', 'department' ];
|
||||
|
||||
useEffect(() => {
|
||||
if (!data?.data.length) {
|
||||
setLostDoctors([]);
|
||||
return;
|
||||
}
|
||||
let canceled = false;
|
||||
|
||||
Promise.all(
|
||||
data.data.map(item => {
|
||||
const fetchString = fetchParams.filter((param => Boolean(item[param]))).map(param => `${param}=${item[param]}`).join('&');
|
||||
return axios.get(apiUrl(`/idoctor/list?${fetchString}`), {
|
||||
headers: { Authorization: `Bearer ${localStorage.getItem('token')}` }
|
||||
})
|
||||
.then(res => {
|
||||
return ({ doctor: res?.data?.data[0], emptyLocation: item });
|
||||
})
|
||||
}
|
||||
)
|
||||
).then(results => {
|
||||
if (!canceled) {
|
||||
setLostDoctors(results.filter(Boolean));
|
||||
}
|
||||
}).catch(() => {
|
||||
if (!canceled) {
|
||||
setLostDoctors([]);
|
||||
}
|
||||
});
|
||||
return () => { canceled = true };
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [data]);
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
error,
|
||||
lostDoctors,
|
||||
filials: filials?.data || [],
|
||||
departments: departments?.data || [],
|
||||
regions,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { useGetSpecialistsQuery } from '../api/apiSpecialist';
|
||||
import { selectRegions } from '../store/slice/regionSlice';
|
||||
|
||||
export function useNewSpecialistId() {
|
||||
const regions = useSelector(selectRegions);
|
||||
const regionIds = Object.keys(regions);
|
||||
|
||||
const queries = regionIds.map(rid => useGetSpecialistsQuery(rid));
|
||||
const isLoading = queries.some(q => q.isLoading);
|
||||
const error = queries.find(q => q.error)?.error;
|
||||
const allData = queries.flatMap(q => q.data ?? []);
|
||||
const newId = Math.max.apply(Math,
|
||||
allData.map(( specialist ) => Number(specialist.id))
|
||||
) + 1;
|
||||
|
||||
return newId
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import React from "react";
|
||||
|
||||
export const useOutsideClick = (ref, onOutsideClick) => {
|
||||
React.useEffect(() => {
|
||||
const handleClick = (e) => {
|
||||
if (ref.current && !ref.current.contains(e.target)) {
|
||||
onOutsideClick();
|
||||
}
|
||||
};
|
||||
document.addEventListener('mousedown', handleClick);
|
||||
return () => document.removeEventListener('mousedown', handleClick);
|
||||
}, [ref, onOutsideClick]);
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { useMemo } from 'react';
|
||||
|
||||
export const useSortedPaginated = (data, itemsPerPage, sortBy, sortDirection, currentPage) => {
|
||||
const sorted = useMemo(() => {
|
||||
return [...data].sort((a, b) => {
|
||||
let aValue = a[sortBy], bValue = b[sortBy];
|
||||
|
||||
if (sortBy === 'experience') {
|
||||
aValue = typeof aValue === 'number' ? aValue : 0;
|
||||
bValue = typeof bValue === 'number' ? bValue : 0;
|
||||
}
|
||||
|
||||
if (sortBy === 'locations') {
|
||||
aValue = aValue === 'нет данных' ? 'я' : aValue;
|
||||
bValue = bValue === 'нет данных' ? 'я' : bValue;
|
||||
}
|
||||
|
||||
if (aValue == null || bValue == null) return 0
|
||||
|
||||
if (typeof aValue === 'number') return sortDirection === 'asc'
|
||||
? aValue - bValue
|
||||
: bValue - aValue
|
||||
|
||||
if (typeof aVal === 'string' && typeof bVal === 'string') {
|
||||
aValue = aValue.replaceAll(' ', '');
|
||||
bValue = bValue.replaceAll(' ', '');
|
||||
}
|
||||
|
||||
return sortDirection === 'asc'
|
||||
? String(aValue).localeCompare(String(bValue))
|
||||
: String(bValue).localeCompare(String(aValue))
|
||||
});
|
||||
}, [data, sortBy, sortDirection]);
|
||||
|
||||
const totalPages = Math.ceil(sorted.length / itemsPerPage);
|
||||
|
||||
const paginated = useMemo(() => {
|
||||
const start = (currentPage - 1) * itemsPerPage;
|
||||
return sorted.slice(start, start + itemsPerPage);
|
||||
}, [sorted, currentPage, itemsPerPage]);
|
||||
|
||||
return { paginated, totalPages };
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
export const useSorting = (initialKey = 'id', initialDir = 'asc') => {
|
||||
const [sortBy, setSortBy] = useState(initialKey);
|
||||
const [sortDirection, setSortDirection] = useState(initialDir);
|
||||
|
||||
const handleSort = useCallback(
|
||||
key => {
|
||||
setSortDirection(prev => (sortBy === key ? (prev === 'asc' ? 'desc' : 'asc') : 'asc'));
|
||||
setSortBy(key);
|
||||
},
|
||||
[sortBy]
|
||||
);
|
||||
|
||||
return { sortBy, sortDirection, handleSort };
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import axios from 'axios';
|
||||
import { useSelector } from 'react-redux';
|
||||
|
||||
import { apiUrl } from '@/config/api';
|
||||
|
||||
import { useGetSpecialistsQuery, useGetSpecialistQuery } from '../api/apiSpecialist';
|
||||
import { useGetKodopersQuery } from '../api/apiKodoper';
|
||||
import { useGetFilialsQuery } from '../api/apiFilial';
|
||||
import { useGetDepartmentsQuery } from '../api/apiDepartment';
|
||||
import { selectRegions } from '../store/slice/regionSlice';
|
||||
|
||||
export function useSpecialist(id) {
|
||||
const { data: specialist, isLoading, error } = useGetSpecialistQuery(id);
|
||||
const [kodoperDetails, setKodoperDetails] = useState([]);
|
||||
const filialsQuery = useGetFilialsQuery();
|
||||
const filials = filialsQuery.data ?? [];
|
||||
|
||||
const departmentsQuery = useGetDepartmentsQuery();
|
||||
const departments = departmentsQuery.data ?? [];
|
||||
const regions = useSelector(selectRegions);
|
||||
|
||||
useEffect(() => {
|
||||
if (!specialist?.kodoper?.length) {
|
||||
setKodoperDetails([]);
|
||||
return;
|
||||
}
|
||||
let canceled = false;
|
||||
|
||||
Promise.all(
|
||||
specialist.kodoper.map(code =>
|
||||
axios.get(apiUrl(`/pricelist/list?search=${code}`), {
|
||||
headers: { Authorization: `Bearer ${localStorage.getItem('token')}` }
|
||||
})
|
||||
.then(res => {
|
||||
return (res.data.data || []).find(item => String(item.kodoper) === String(code)) || null;
|
||||
})
|
||||
)
|
||||
).then(results => {
|
||||
if (!canceled) {
|
||||
setKodoperDetails(results.filter(Boolean));
|
||||
}
|
||||
}).catch(() => {
|
||||
if (!canceled) {
|
||||
setKodoperDetails([]);
|
||||
}
|
||||
});
|
||||
return () => { canceled = true };
|
||||
}, [specialist]);
|
||||
|
||||
return {
|
||||
isLoading,
|
||||
error,
|
||||
specialist: specialist ?? null,
|
||||
filials,
|
||||
departments,
|
||||
regions,
|
||||
kodoperDetails,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
import { useMemo } from "react";
|
||||
|
||||
export function useSpecialistFilter({ regionId, filialId, searchValue }, queries, filials, regionsMap, currentYear) {
|
||||
return useMemo(() => {
|
||||
const flatData =
|
||||
regionId === 'all'
|
||||
? queries.flatMap(q => q.data || [])
|
||||
: queries.find(q => q.originalArgs === regionId)?.data || [];
|
||||
|
||||
console.log(queries)
|
||||
|
||||
const formatted = flatData.map(s => {
|
||||
const experience = s.experience ? currentYear - s.experience : null;
|
||||
const location = s.locations[0];
|
||||
const filial = filials.find(f => f.id === location?.filial);
|
||||
return {
|
||||
...s,
|
||||
experience,
|
||||
locations: filial ? `${regionsMap[filial.regionId]}, ${filial.shortName}` : 'нет данных',
|
||||
filialId: filial?.id || null,
|
||||
activeLabel: s.active ? 'да' : 'нет',
|
||||
scheduleLabel: s.displaySchedule ? 'да' : 'нет',
|
||||
};
|
||||
});
|
||||
|
||||
const byFilial = filialId === 'all' ? formatted : formatted.filter(s => s.filialId === Number(filialId));
|
||||
|
||||
const search = searchValue.trim().toLowerCase().replaceAll(' ', '');
|
||||
if (!search) return byFilial;
|
||||
return byFilial.filter(s => {
|
||||
if ( String(s.id).includes(search) ) return true
|
||||
if ( s.nameString.replaceAll(' ', '').toLowerCase().includes(search) ) return true
|
||||
if ( s.experience ) {
|
||||
if ( String(s.experience ?? '').includes(search) ) return true
|
||||
}
|
||||
if ( s.post ) {
|
||||
if ( s.post.replaceAll(' ', '').toLowerCase().includes(search) ) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
);
|
||||
}, [regionId, filialId, searchValue, queries, filials, regionsMap, currentYear]);
|
||||
}
|
||||
Reference in New Issue
Block a user