copied the code from the working repo
This commit is contained in:
175
mtucijobsweb/fsd/widgets/Search/SearchWidget.tsx
Normal file
175
mtucijobsweb/fsd/widgets/Search/SearchWidget.tsx
Normal file
@@ -0,0 +1,175 @@
|
||||
'use client'
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { useQuery } from 'react-query';
|
||||
import { searchJobs } from '@/api/api';
|
||||
import { Input, Button, Spin, List, Select, Checkbox, InputNumber, Card } from 'antd';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import style from './SearchWidget.module.scss';
|
||||
import { JobData } from '@/types/types';
|
||||
import { skillsOptions } from '@/fsd/entities/Resume/data';
|
||||
import { initThemeParams } from '@tma.js/sdk-react';
|
||||
|
||||
const { Option } = Select;
|
||||
|
||||
const SearchWidget: React.FC = () => {
|
||||
const [query, setQuery] = useState('');
|
||||
const [year, setYear] = useState<number | undefined>();
|
||||
const [qualification, setQualification] = useState<boolean | undefined>();
|
||||
const [time, setTime] = useState<string[]>([]);
|
||||
const [salary, setSalary] = useState<number | undefined>();
|
||||
const [hardskills, setHardskills] = useState<string[]>([]);
|
||||
const [searchResults, setSearchResults] = useState<JobData[]>([]);
|
||||
const [themeParams] = initThemeParams();
|
||||
|
||||
// Функция для формирования объекта параметров
|
||||
const buildQueryParams = () => {
|
||||
const params: any = {}; // Или укажите более точный тип, соответствующий JobsSearch
|
||||
|
||||
if (year !== undefined) {
|
||||
params.year = year;
|
||||
}
|
||||
if (qualification !== undefined) {
|
||||
params.qualification = qualification;
|
||||
}
|
||||
if (time.length > 0) {
|
||||
params.time = time; // здесь может потребоваться изменить на массив строк
|
||||
}
|
||||
if (salary !== undefined) {
|
||||
params.salary = salary;
|
||||
}
|
||||
if (hardskills.length > 0) {
|
||||
params.hardskills = hardskills;
|
||||
}
|
||||
if (query) {
|
||||
params.search = query;
|
||||
}
|
||||
|
||||
return params; // Возвращаем объект вместо строки
|
||||
};
|
||||
|
||||
// Вызов useQuery с объектом
|
||||
const { data, error, isLoading, refetch } = useQuery<JobData[]>(
|
||||
['searchJobs', buildQueryParams()],
|
||||
() => {
|
||||
const queryParams = buildQueryParams(); // Получаем объект параметров
|
||||
return searchJobs(queryParams); // Передаём объект в функцию
|
||||
},
|
||||
{ enabled: false, refetchOnWindowFocus: false, retry: false }
|
||||
);
|
||||
|
||||
// Используем useEffect для обновления searchResults, когда запрос завершен
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
setSearchResults(data);
|
||||
}
|
||||
}, [data]);
|
||||
|
||||
const handleSearch = () => {
|
||||
refetch();
|
||||
};
|
||||
|
||||
if (isLoading) return <Spin size='large' className={style.spin} />;
|
||||
if (error)
|
||||
return <div className={style.error}>Ошибка при поиске вакансий</div>;
|
||||
|
||||
return (
|
||||
<div className={style.container}>
|
||||
<div className={style.form}>
|
||||
<Input
|
||||
placeholder='Поиск по названию вакансии или компании...'
|
||||
value={query}
|
||||
onChange={e => setQuery(e.target.value)}
|
||||
prefix={<SearchOutlined />}
|
||||
style={{ marginBottom: 20 }}
|
||||
/>
|
||||
|
||||
<Select
|
||||
placeholder='Выберите Курс'
|
||||
style={{ width: '100%', marginBottom: 20 }}
|
||||
onChange={value => setYear(value)}
|
||||
value={year}
|
||||
>
|
||||
<Option value={1}>1</Option>
|
||||
<Option value={2}>2</Option>
|
||||
<Option value={3}>3</Option>
|
||||
<Option value={4}>4</Option>
|
||||
{/* Добавьте другие годы по необходимости */}
|
||||
</Select>
|
||||
|
||||
<Checkbox
|
||||
checked={qualification}
|
||||
onChange={e => setQualification(e.target.checked)}
|
||||
style={{ marginBottom: 20, color: themeParams.textColor }}
|
||||
>
|
||||
Требуется квалификация
|
||||
</Checkbox>
|
||||
|
||||
<Select
|
||||
mode='multiple'
|
||||
placeholder='Выберите занятость'
|
||||
style={{ width: '100%', marginBottom: 20 }}
|
||||
onChange={value => setTime(value)}
|
||||
value={time}
|
||||
>
|
||||
<Option value='20'>20</Option>
|
||||
<Option value='30'>30</Option>
|
||||
<Option value='40'>40</Option>
|
||||
</Select>
|
||||
|
||||
<InputNumber
|
||||
placeholder='Минимальная зарплата'
|
||||
value={salary}
|
||||
onChange={value => setSalary(value !== null ? value : undefined)}
|
||||
style={{ width: '100%', marginBottom: 20 }}
|
||||
/>
|
||||
|
||||
<Select
|
||||
mode='multiple'
|
||||
placeholder='Выберите hard skills'
|
||||
style={{ width: '100%', marginBottom: 20 }}
|
||||
onChange={value => setHardskills(value)}
|
||||
value={hardskills}
|
||||
options={skillsOptions.map(skill => ({ value: skill, label: skill }))}
|
||||
/>
|
||||
|
||||
<Button type='primary' onClick={handleSearch} style={{ width: '100%' }}>
|
||||
Поиск
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<div style={{ marginTop: 20 }}>
|
||||
{isLoading && <Spin size='large' />}
|
||||
{searchResults.length > 0 ? (
|
||||
<div className={style.cardWrapper}>
|
||||
{searchResults.map((item: JobData) => (
|
||||
<Card
|
||||
key={item.Email} // Предположим, что Email уникален для вакансий
|
||||
title={item.Job_name}
|
||||
bordered={false}
|
||||
style={{ marginBottom: 20 }}
|
||||
className={style.card}
|
||||
>
|
||||
<p>Год: {item.Year}</p>
|
||||
<p>Квалификация: {item.Qualification ? 'Да' : 'Нет'}</p>
|
||||
<p>Зарплата: {item.Salary}</p>
|
||||
<p>Soft Skills: {item.Soft_skills}</p>
|
||||
<p>Обязанности: {item.Responsibilities}</p>
|
||||
<p>
|
||||
Email: <a href={`mailto:${item.Email}`}>{item.Email}</a>
|
||||
</p>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
!isLoading && (
|
||||
<div style={{ color: themeParams.textColor }}>
|
||||
Вакансии не найдены
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default SearchWidget;
|
||||
Reference in New Issue
Block a user