dodanie nowych komponentow oraz dodanie walidacji propTypes
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
parent
10103fb1a1
commit
256bd8a0ee
@ -7,7 +7,7 @@
|
|||||||
<link rel="icon" href="../icon/favicon.ico"/>
|
<link rel="icon" href="../icon/favicon.ico"/>
|
||||||
<!-- todo ICONs -->
|
<!-- todo ICONs -->
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>izaac frontend</title>
|
<title>Izaac - praca dla inżynierów</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
27
src/App.jsx
27
src/App.jsx
@ -7,38 +7,29 @@ import { Route, Routes } from "react-router-dom";
|
|||||||
import Contact from "./components/Contact";
|
import Contact from "./components/Contact";
|
||||||
import Mininav from "./components/Mininav";
|
import Mininav from "./components/Mininav";
|
||||||
import AddJobListing from "./components/AddJobListing";
|
import AddJobListing from "./components/AddJobListing";
|
||||||
import { useState, useEffect } from "react";
|
|
||||||
import axios from "axios";
|
|
||||||
import EmployerPanel from "./components/EmployerPanel";
|
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
|
|
||||||
const loc = () => {
|
|
||||||
if (location.pathname.startsWith("work/jobposting")) {
|
|
||||||
return "";
|
|
||||||
} else {
|
|
||||||
return "overflow-hidden";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return (
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
<div className={`bg-white w-full ${loc}`}>
|
<div className={`bg-white w-full`}>
|
||||||
<div className={`${styles.paddingX} ${styles.flexCenter} border-b-2`}>
|
<div className={`${styles.paddingX} ${styles.flexCenter} border-b-2 relative`}>
|
||||||
<Mininav />
|
{/* <Mininav /> */}
|
||||||
<div className={`${styles.boxWidth}`}>
|
<div className={`${styles.boxWidth} mx-auto`}>
|
||||||
<NavBar />
|
<NavBar />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={`${styles.flexStart}`}>
|
<div className={`${styles.flexStart} mt-18 sm:mt-0`}>
|
||||||
<div className={`${styles.boxWidth2} `}>
|
<div className={`${styles.boxWidth2} `}>
|
||||||
<Routes>
|
<Routes>
|
||||||
<Route path="/home" element={<Home />} />
|
<Route path="/home" element={<Home />} />
|
||||||
<Route path="/work" element={<WorkApp />} />
|
<Route path="/work" element={<WorkApp />} />
|
||||||
<Route path="/work/postings" element={<WorkApp />} />
|
<Route path="/work/joboffers" element={<WorkApp />} />
|
||||||
<Route path="/contact" element={<Contact />} />
|
<Route path="/contact" element={<Contact />} />
|
||||||
<Route path="/work/jobposting" element={<AddJobListing />} />
|
<Route path="/work/addjoboffer" element={<AddJobListing />} />
|
||||||
<Route path="/employerpanel" element={<EmployerPanel />} />
|
<Route path="/work/joboffers/:id" element={<WorkApp/>} />
|
||||||
|
{/* <Route path="/employerpanel" element={<EmployerPanel />} /> */}
|
||||||
{/* Add more routes as needed */}
|
{/* Add more routes as needed */}
|
||||||
</Routes>
|
</Routes>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import StepOneJoblisting from './StepOneJoblisting';
|
import StepOneJoblisting from './StepOneJoblisting';
|
||||||
import StepTwoJoblisting from './StepTwoJoblisting';
|
import StepTwoJoblisting from './StepTwoJoblisting';
|
||||||
import StepThreeJoblisting from './StepThreeJoblisting';
|
import StepThreeJoblisting from './StepThreeJoblisting';
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
import propTypes from 'prop-types'
|
||||||
|
|
||||||
const Category = (props) => {
|
const Category = (props) => {
|
||||||
return (
|
return (
|
||||||
@ -15,4 +15,11 @@ const Category = (props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Category.propTypes = {
|
||||||
|
name: propTypes.string,
|
||||||
|
func: propTypes.func,
|
||||||
|
small: propTypes.bool,
|
||||||
|
last: propTypes.bool
|
||||||
|
}
|
||||||
|
|
||||||
export default Category
|
export default Category
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React from "react";
|
|
||||||
import { ogloszenia } from "../consts";
|
import { ogloszenia } from "../consts";
|
||||||
import ListingSmall from "./ListingSmall";
|
import ListingSmall from "./ListingSmall";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|||||||
@ -1,30 +1,128 @@
|
|||||||
import React from 'react'
|
|
||||||
import Search from './Search'
|
import Search from './Search'
|
||||||
|
import { useEffect, useState } from 'react';
|
||||||
|
import { categories, work_from_home, employment_types } from '../consts';
|
||||||
|
import propTypes from 'prop-types';
|
||||||
|
import Selector from './Selector';
|
||||||
const Filter = (props) => {
|
const Filter = (props) => {
|
||||||
if (!props.isOpen) return null;
|
useEffect(() => {
|
||||||
return (
|
console.log(props.searchQuery)
|
||||||
<div className={`sticky top-24 z-20 bg-gray-100 flex flex-wrap place-items-center items-center slide-container py-2 ${!props.isOpen ? '' : 'expanded'}`}>
|
console.log(selectedCategories)
|
||||||
<Search label='Wyszukaj ogłoszenie'
|
console.log(selectedWorkFromHome)
|
||||||
placeholder='Wpisz nazwę stanowiska...' />
|
console.log(selectedEmploymentTypes)
|
||||||
<Search label='Lokalizacja'
|
console.log(valueminSalary)
|
||||||
placeholder='Wpisz lokalizację...' />
|
}, [props.searchQuery]);
|
||||||
<Search label='Min. wynagrodzenie'
|
|
||||||
placeholder='Wpisz kwotę minimalną...' />
|
|
||||||
<Search label='Max. wynagrodzenie'
|
|
||||||
placeholder='Wpisz kwotę maksymalną...' />
|
|
||||||
|
|
||||||
<button className='bg-gray-600 text-white py-3 px-12 col-span-2
|
const [selectedCategories, setSelectedCategories] = useState([]);
|
||||||
mx-auto rounded-md font-semibold text-xl hover:bg-gray-500 duration-150
|
const [selectedWorkFromHome, setSelectedWorkFromHome] = useState([]);
|
||||||
mt-3
|
const [selectedEmploymentTypes, setSelectedEmploymentTypes] = useState([]);
|
||||||
'
|
const [valueminSalary, setValueminSalary] = useState('');
|
||||||
onClick={props.onClicked}
|
const [valuemaxSalary, setValuemaxSalary] = useState('');
|
||||||
|
const [valueName, setValueName] = useState('');
|
||||||
|
const [valueLocalization, setValueLocalization] = useState('');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setSelectedCategories([])
|
||||||
|
setSelectedWorkFromHome([])
|
||||||
|
setSelectedEmploymentTypes([])
|
||||||
|
setValueminSalary('')
|
||||||
|
setValuemaxSalary('')
|
||||||
|
setValueName('')
|
||||||
|
setValueLocalization('')
|
||||||
|
}, [props.clearSearchQuery])
|
||||||
|
|
||||||
|
const handle_checked_change = (e) => {
|
||||||
|
switch (e.target.name) {
|
||||||
|
case 'categories':
|
||||||
|
if (e.target.checked) {
|
||||||
|
setSelectedCategories([...selectedCategories, e.target.value]);
|
||||||
|
} else {
|
||||||
|
setSelectedCategories(selectedCategories.filter(category => category !== e.target.value));
|
||||||
|
}
|
||||||
|
props.setSearchQuery(prevState =>
|
||||||
|
({...prevState,
|
||||||
|
categories: e.target.checked ? [...(prevState.categories || []), e.target.value] : (prevState.categories || []).filter(category => category !== e.target.value)}));
|
||||||
|
break;
|
||||||
|
case 'work_from_home':
|
||||||
|
if (e.target.checked) {
|
||||||
|
setSelectedWorkFromHome([...selectedWorkFromHome, e.target.value]);
|
||||||
|
} else {
|
||||||
|
setSelectedWorkFromHome(selectedCategories.filter(work_from_home => work_from_home !== e.target.value));
|
||||||
|
}
|
||||||
|
props.setSearchQuery(prevState =>
|
||||||
|
({...prevState,
|
||||||
|
work_from_home: e.target.checked ? [...(prevState.work_from_home || []), e.target.value] : (prevState.work_from_home || []).filter(work_from_home => work_from_home !== e.target.value)}));
|
||||||
|
break;
|
||||||
|
case 'employment':
|
||||||
|
if (e.target.checked) {
|
||||||
|
setSelectedEmploymentTypes([...selectedEmploymentTypes, e.target.value]);
|
||||||
|
} else {
|
||||||
|
setSelectedEmploymentTypes(selectedCategories.filter(employment => employment !== e.target.value));
|
||||||
|
}
|
||||||
|
props.setSearchQuery(prevState =>
|
||||||
|
({...prevState,
|
||||||
|
employment: e.target.checked ? [...(prevState.employment || []), e.target.value] : (prevState.employment || []).filter(employment => employment !== e.target.value)}));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return (
|
||||||
|
// idea - make the page whole page grayed out and only the filter is visible
|
||||||
|
<div className={`z-10 bg-dimWhite collapsible px-3 sm:px-4 ${!props.isOpen ? '' : 'expanded border-4'}`}>
|
||||||
|
<div className='grid grid-cols-2 sm:grid-cols-3 mb-2'>
|
||||||
|
<div className='hidden sm:block'></div>
|
||||||
|
<p className='mx-auto mt-3 text-center font-poppins font-semibold text-xl text-gray-600'>Filtry</p>
|
||||||
|
|
||||||
|
<button className='rounded-xl mt-4 ph-6 w-32 bg-slate-400 hover:bg-slate-600 duration-100 ' onClick={props.clearSearchQuery}>
|
||||||
|
<span className='p-2 text-sm font-bold text-center font-poppins text-white'>Wyczyść filtry</span>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Search label='Wyszukaj ogłoszenie'
|
||||||
|
placeholder='Wpisz nazwę stanowiska...'
|
||||||
|
name='name'
|
||||||
|
setSearchQuery={props.setSearchQuery}
|
||||||
|
_type='text'
|
||||||
|
value={props.searchQuery.name || ''}/>
|
||||||
|
<Search label='Lokalizacja'
|
||||||
|
placeholder='Wpisz lokalizację...'
|
||||||
|
name='localization'
|
||||||
|
_type='text'
|
||||||
|
setSearchQuery={props.setSearchQuery}
|
||||||
|
value={props.searchQuery.localization || ''} />
|
||||||
|
<Search label='Min. wynagrodzenie'
|
||||||
|
placeholder='Wpisz kwotę minimalną...'
|
||||||
|
name='min_salary'
|
||||||
|
_type='text'
|
||||||
|
setSearchQuery={props.setSearchQuery}
|
||||||
|
value={props.searchQuery.min_salary || '' } />
|
||||||
|
<Search label='Max. wynagrodzenie'
|
||||||
|
placeholder='Wpisz kwotę maksymalną...'
|
||||||
|
name='max_salary'
|
||||||
|
setSearchQuery={props.setSearchQuery}
|
||||||
|
_type='text'
|
||||||
|
value={props.searchQuery.max_salary || ''}/>
|
||||||
|
<Selector value_to_map_from={categories} name='Kategorie' inputname='categories' onChange={handle_checked_change} state={selectedCategories}/>
|
||||||
|
<Selector value_to_map_from={work_from_home} s name='Praca zdalna' inputname='work_from_home' state={selectedWorkFromHome} onChange={handle_checked_change}/>
|
||||||
|
<Selector value_to_map_from={employment_types} name='Typ kontraktu' inputname='employment' state={selectedEmploymentTypes} onChange={handle_checked_change} />
|
||||||
|
|
||||||
|
<button className='bg-gray-600 text-white py-1 sm:py-3 px-12 col-span-2 mx-auto rounded-md font-semibold text-xl hover:bg-gray-500 duration-150 my-3 sm:my-5 sm:min-h-full'
|
||||||
|
onClick={props.onClick}
|
||||||
>
|
>
|
||||||
Filtruj
|
Filtruj
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
};
|
||||||
|
|
||||||
export default Filter
|
Filter.propTypes = {
|
||||||
|
isOpen: propTypes.bool,
|
||||||
|
searchQuery: propTypes.object,
|
||||||
|
setSearchQuery: propTypes.func,
|
||||||
|
categories: propTypes.array,
|
||||||
|
clearSearchQuery: propTypes.func,
|
||||||
|
onClick: propTypes.func
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Filter;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
|
||||||
import styles from '../style'
|
import styles from '../style'
|
||||||
const Home = () => {
|
const Home = () => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
import { useState, useRef, useEffect } from 'react';
|
||||||
import { placeholderImage } from '../assets';
|
import { placeholderImage } from '../assets';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import propTypes from 'prop-types';
|
||||||
|
|
||||||
const ImageUpload = ({setFormData, data}) => {
|
const ImageUpload = ({setFormData, data}) => {
|
||||||
const [imageSrc, setImageSrc] = useState(placeholderImage);
|
const [imageSrc, setImageSrc] = useState(placeholderImage);
|
||||||
@ -83,4 +83,9 @@ const ImageUpload = ({setFormData, data}) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ImageUpload.propTypes = {
|
||||||
|
setFormData: propTypes.func,
|
||||||
|
data: propTypes.object
|
||||||
|
};
|
||||||
|
|
||||||
export default ImageUpload;
|
export default ImageUpload;
|
||||||
|
|||||||
@ -9,7 +9,7 @@ const JobOfferContent = ({ id, skills }) => {
|
|||||||
|
|
||||||
const fetchJobOfferById = async (jobId) => {
|
const fetchJobOfferById = async (jobId) => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get(`https://izaac.knck.pl/api/jobposting/joboffers/${jobId}`);
|
const response = await axios.get(`https://izaac.knck.pl/api/jobposting/joboffers/${jobId}/?format=json`);
|
||||||
setJobOffer(response.data);
|
setJobOffer(response.data);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to fetch job offer:', error);
|
console.error('Failed to fetch job offer:', error);
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
import React from 'react'
|
|
||||||
import { IzaacLOGO } from '../assets'
|
|
||||||
|
|
||||||
const ListingSmall = ({ id, name, company_name, min_salary, max_salary, require_salary, index, onClick, _class, image }) => {
|
import { IzaacLOGO } from '../assets'
|
||||||
|
import propTypes from 'prop-types'
|
||||||
|
|
||||||
|
const ListingSmall = ({ id, name, company_name, min_salary, max_salary, require_salary, index, onClick, _class, image, selected, blur }) => {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={id}
|
key={id}
|
||||||
className={`flex flex-row items-center gap-4 drop-shadow cursor-pointer mb-2 sm:mr-4 mr-0 text-xl font-bold border rounded-[10px] p-2 sm: px-4 hover:border-l-8 hover:border-zinc-500 duration-300 ${index % 2 === 0 ? 'bg-gray-200' : 'bg-gray-300'} ${_class}`}
|
className={`flex flex-row ml-1 w-[98vw] sm:w-full items-center gap-4 drop-shadow cursor-pointer mb-2 sm:mr-4 mr-4 text-xl font-bold border rounded-[10px] p-2 sm:px-4 hover:border-l-8 hover:border-zinc-500 duration-300 blur-transition ${index % 2 === 0 ? 'bg-gray-200' : 'bg-gray-300'} ${_class} ${selected ? 'border-l-8 border-zinc-500 bg-gray-400' : 'border-l-8 border-transparent'} `}
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
>
|
>
|
||||||
<div className='flex-shrink-0 w-[6rem] h-[6rem] bg-white rounded-lg flex items-center justify-center'>
|
<div className='flex-shrink-0 w-[6rem] h-[6rem] bg-white rounded-lg flex items-center justify-center'>
|
||||||
@ -14,7 +15,7 @@ const ListingSmall = ({ id, name, company_name, min_salary, max_salary, require_
|
|||||||
</div>
|
</div>
|
||||||
<div className='flex-grow flex flex-col justify-between'>
|
<div className='flex-grow flex flex-col justify-between'>
|
||||||
<p className='text-base font-bold text-left tracking-wide'>{name}</p>
|
<p className='text-base font-bold text-left tracking-wide'>{name}</p>
|
||||||
<p className='text-sm text-left text-gray-600'>{company_name}</p>
|
<p className='text-xs text-left text-gray-600'>{company_name}</p>
|
||||||
{/* Wyświetlenie wynagrodzenia pod nazwą, jeśli jest wymagane */}
|
{/* Wyświetlenie wynagrodzenia pod nazwą, jeśli jest wymagane */}
|
||||||
{require_salary && (
|
{require_salary && (
|
||||||
<p className='text-xs font-semibold text-left tracking-widest text-slate-800 mt-2'>{min_salary} - {max_salary} PLN</p>
|
<p className='text-xs font-semibold text-left tracking-widest text-slate-800 mt-2'>{min_salary} - {max_salary} PLN</p>
|
||||||
@ -24,4 +25,19 @@ const ListingSmall = ({ id, name, company_name, min_salary, max_salary, require_
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ListingSmall;
|
export default ListingSmall;
|
||||||
|
|
||||||
|
ListingSmall.propTypes = {
|
||||||
|
id: propTypes.number,
|
||||||
|
name: propTypes.string,
|
||||||
|
company_name: propTypes.string,
|
||||||
|
min_salary: propTypes.number,
|
||||||
|
max_salary: propTypes.number,
|
||||||
|
require_salary: propTypes.bool,
|
||||||
|
index: propTypes.number,
|
||||||
|
onClick: propTypes.func,
|
||||||
|
_class: propTypes.string,
|
||||||
|
image: propTypes.string,
|
||||||
|
selected: propTypes.bool,
|
||||||
|
blur: propTypes.string
|
||||||
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
import propTypes from 'prop-types';
|
||||||
import styles from '../style';
|
import styles from '../style';
|
||||||
|
|
||||||
const Login = ({isOpen, onClose}) => {
|
const Login = ({isOpen, onClose}) => {
|
||||||
@ -31,4 +31,9 @@ const Login = ({isOpen, onClose}) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Login.propTypes = {
|
||||||
|
isOpen: propTypes.bool,
|
||||||
|
onClose: propTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
export default Login
|
export default Login
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import React, { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import Register from './Register';
|
import Register from './Register';
|
||||||
import Login from './Login';
|
import Login from './Login';
|
||||||
import { BrowserRouter as Router } from "react-router-dom";
|
|
||||||
import { Route, Routes } from "react-router-dom";
|
|
||||||
|
|
||||||
const Mininav = () => {
|
const Mininav = () => {
|
||||||
const [isPopupOpen, setPopupOpen] = useState(false)
|
const [isPopupOpen, setPopupOpen] = useState(false)
|
||||||
@ -17,7 +16,7 @@ const Mininav = () => {
|
|||||||
<>
|
<>
|
||||||
<div className='bg-gray-500 h-5 absolute w-full top-0 flex justify-end items-center z-50'>
|
<div className='bg-gray-500 h-5 absolute w-full top-0 flex justify-end items-center z-50'>
|
||||||
{/* Link otwierający modal */}
|
{/* Link otwierający modal */}
|
||||||
<a href="/employerpanel" className='text-white font-poppins font-semibold text-xs'>Panel pracodawcy</a>
|
{/* <a href="/employerpanel" className='text-white font-poppins font-semibold text-xs'>Panel pracodawcy</a> */}
|
||||||
<button onClick={openPopup} className='text-white font-poppins font-semibold text-xs mx-12'>
|
<button onClick={openPopup} className='text-white font-poppins font-semibold text-xs mx-12'>
|
||||||
Rejestracja
|
Rejestracja
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import React from 'react'
|
|
||||||
import { linki, linki_home } from '../consts';
|
import { linki, linki_home } from '../consts';
|
||||||
import { close, search, menu, IzaacLOGO} from '../assets';
|
import { close, search, menu, IzaacLOGO} from '../assets';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useLocation } from 'react-router-dom';
|
import { useLocation } from 'react-router-dom';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import Mininav from './Mininav';
|
import Mininav from './Mininav';
|
||||||
|
|
||||||
const NavBar = () => {
|
const NavBar = () => {
|
||||||
const[toggle, setToggle] = useState(false)
|
const[toggle, setToggle] = useState(false)
|
||||||
const[toggleSearch, setToggleSearch] = useState(false)
|
const[toggleSearch, setToggleSearch] = useState(false)
|
||||||
@ -20,7 +20,7 @@ const NavBar = () => {
|
|||||||
const currentLinks = getLinks()
|
const currentLinks = getLinks()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<nav className='w-full flex pt-7 justify-between items-center navbar '>
|
<nav className='fixed top-0 left-0 sm:relative z-30 w-full flex pt-4 justify-between items-center navbar bg-white px-8'>
|
||||||
|
|
||||||
<img src={IzaacLOGO} alt="izaac" className='md:w-[200px] w-[120px]'/>
|
<img src={IzaacLOGO} alt="izaac" className='md:w-[200px] w-[120px]'/>
|
||||||
|
|
||||||
@ -76,5 +76,4 @@ const NavBar = () => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export default NavBar
|
export default NavBar
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React from 'react'
|
|
||||||
import styles from '../style';
|
import styles from '../style';
|
||||||
|
import propTypes from 'prop-types';
|
||||||
|
|
||||||
const Register = ({isOpen, onClose}) => {
|
const Register = ({isOpen, onClose}) => {
|
||||||
if (!isOpen) return null;
|
if (!isOpen) return null;
|
||||||
@ -44,5 +44,8 @@ const Register = ({isOpen, onClose}) => {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Register.propTypes = {
|
||||||
|
isOpen: propTypes.bool,
|
||||||
|
onClose: propTypes.func
|
||||||
|
}
|
||||||
export default Register
|
export default Register
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import React, { useState, useEffect } from 'react'
|
import { useState, useEffect } from 'react'
|
||||||
import styles from '../style'
|
import propTypes from 'prop-types'
|
||||||
|
|
||||||
import {employment_types, work_from_home } from '../consts'
|
import {employment_types, work_from_home } from '../consts'
|
||||||
|
|
||||||
@ -112,5 +112,18 @@ const Salary = ({handleChange, formData, removeFields, setFormData}) => {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Salary.propTypes = {
|
||||||
|
handleChange: propTypes.func,
|
||||||
|
formData: propTypes.object,
|
||||||
|
removeFields: propTypes.func,
|
||||||
|
setFormData: propTypes.func,
|
||||||
|
min_salary: propTypes.string,
|
||||||
|
max_salary: propTypes.string,
|
||||||
|
require_salary: propTypes.bool,
|
||||||
|
employment_type: propTypes.string,
|
||||||
|
work_from_home: propTypes.string
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
export default Salary
|
export default Salary
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,61 @@
|
|||||||
import React from 'react'
|
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import propTypes from 'prop-types'
|
||||||
|
|
||||||
const Search = (props) => {
|
const Search = (props) => {
|
||||||
return (
|
const [isHovered, setIsHovered] = useState(false)
|
||||||
<div className='grid py-2'>
|
const check_errors = (value, name) => {
|
||||||
<label className="mx-2 text-l font- text-center font-poppins"
|
if ((name === 'max_salary' || name === 'min_salary') && !(value === '' || value === undefined)) {
|
||||||
|
if (isNaN(parseInt(value))) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
console.log(props.value)
|
||||||
|
}, [props.value])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='grid sm:py-1'
|
||||||
|
onMouseEnter={() => setIsHovered(true)}
|
||||||
|
onMouseLeave={() => setIsHovered(false)}
|
||||||
|
>
|
||||||
|
<label className="mx-2 text-l font- text-center font-poppins no-spin-buttons"
|
||||||
htmlFor="search">
|
htmlFor="search">
|
||||||
{props.label}
|
{props.label}
|
||||||
|
<span className='text-sm text-red-700'>
|
||||||
|
{check_errors(props.value, props.name) ? '' : ' *'}
|
||||||
|
</span>
|
||||||
</label>
|
</label>
|
||||||
<input type="text"
|
<input
|
||||||
placeholder={props.placeholder}
|
type={props._type}
|
||||||
className="border-2 border-gray-300
|
value={props.value || ''}
|
||||||
|
placeholder={props.placeholder}
|
||||||
|
name={props.name}
|
||||||
|
id={props.name}
|
||||||
|
onChange={(e) => props.setSearchQuery(prevState => ({...prevState, [props.name]: e.target.value}))}
|
||||||
|
className={`border-2
|
||||||
bg-white h-8 px-5 pr-16 mx-3 rounded-lg
|
bg-white h-8 px-5 pr-16 mx-3 rounded-lg
|
||||||
text-sm focus:outline-none" />
|
text-sm focus:outline-none ${check_errors(props.value, props.name) ? 'border-gray-300': 'border-red-700' }`}/>
|
||||||
|
{isHovered && <div className='text-red-700 text-sm relative'>
|
||||||
|
{check_errors(props.value, props.name) ? '' : 'Wartość musi być liczbą!'}
|
||||||
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Search.propTypes = {
|
||||||
|
label: propTypes.string,
|
||||||
|
placeholder: propTypes.string,
|
||||||
|
name: propTypes.string,
|
||||||
|
setSearchQuery: propTypes.func,
|
||||||
|
value: propTypes.string,
|
||||||
|
_type: propTypes.string
|
||||||
|
}
|
||||||
|
|
||||||
export default Search
|
export default Search
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import propTypes from 'prop-types';
|
||||||
|
|
||||||
const levelMappings = {
|
const levelMappings = {
|
||||||
'N': 'Nice to have',
|
'N': 'Nice to have',
|
||||||
@ -53,4 +53,12 @@ const SelectedSkill = ({ skill_name, skillId ,letter, onLevelChange, removeSkill
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SelectedSkill.propTypes = {
|
||||||
|
skill_name: propTypes.string,
|
||||||
|
skillId: propTypes.number,
|
||||||
|
letter: propTypes.string,
|
||||||
|
onLevelChange: propTypes.func,
|
||||||
|
removeSkillFromList: propTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
export default SelectedSkill;
|
export default SelectedSkill;
|
||||||
|
|||||||
35
src/components/Selector.jsx
Normal file
35
src/components/Selector.jsx
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import propTypes from 'prop-types'
|
||||||
|
|
||||||
|
const Selector = (props) => {
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div className='grid grid-cols-2 sm:gap-[1px]'>
|
||||||
|
<span className='col-span-2 mx-auto text-l font- text-center font-poppins'>{props.name}</span>
|
||||||
|
{props.value_to_map_from.map((value_to_map_from) => (
|
||||||
|
<label key={value_to_map_from.id} className
|
||||||
|
='flex items-center justify-start text-sm font-poppins font-semibold text-gray-600'>
|
||||||
|
<input type='checkbox' name={props.inputname} value={value_to_map_from.id}
|
||||||
|
onChange={props.onChange}
|
||||||
|
className='mr-2'
|
||||||
|
checked={props.state.includes(value_to_map_from.id)}
|
||||||
|
/>
|
||||||
|
|
||||||
|
{value_to_map_from.name}
|
||||||
|
|
||||||
|
</label>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Selector.propTypes = {
|
||||||
|
value_to_map_from: propTypes.array,
|
||||||
|
setSearchQuery: propTypes.func,
|
||||||
|
name: propTypes.string,
|
||||||
|
inputname: propTypes.string,
|
||||||
|
onChange: propTypes.func,
|
||||||
|
state: propTypes.array
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Selector
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import propTypes from 'prop-types';
|
||||||
import SkillRender from './SkillRender';
|
import SkillRender from './SkillRender';
|
||||||
|
|
||||||
|
|
||||||
@ -15,5 +15,9 @@ const SkillsList = ({skillData, skill_names}) => {
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
SkillsList.propTypes = {
|
||||||
|
skillData: propTypes.array,
|
||||||
|
skill_names: propTypes.array,
|
||||||
|
};
|
||||||
|
|
||||||
export default SkillsList;
|
export default SkillsList;
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
import React from 'react'
|
import propTypes from 'prop-types';
|
||||||
|
|
||||||
|
|
||||||
const levelMappings = {
|
const levelMappings = {
|
||||||
'N': 'Nice to have',
|
'N': 'Nice to have',
|
||||||
@ -42,4 +41,10 @@ const SkillRender = ({key, skill, level,}) => {
|
|||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SkillRender.propTypes = {
|
||||||
|
key: propTypes.number,
|
||||||
|
skill: propTypes.string,
|
||||||
|
level: propTypes.string,
|
||||||
|
};
|
||||||
|
|
||||||
export default SkillRender;
|
export default SkillRender;
|
||||||
@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import { useState, useEffect } from 'react';
|
||||||
|
import propTypes from 'prop-types';
|
||||||
import SelectedSkill from './SelectedSkill';
|
import SelectedSkill from './SelectedSkill';
|
||||||
import axios from 'axios';
|
|
||||||
|
|
||||||
const SkillsSelector = ({ formData, setFormData, skills }) => {
|
const SkillsSelector = ({ formData, setFormData, skills }) => {
|
||||||
const [inputValue, setInputValue] = useState('');
|
const [inputValue, setInputValue] = useState('');
|
||||||
@ -101,4 +101,10 @@ const SkillsSelector = ({ formData, setFormData, skills }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SkillsSelector.propTypes = {
|
||||||
|
formData: propTypes.object.isRequired,
|
||||||
|
setFormData: propTypes.func.isRequired,
|
||||||
|
skills: propTypes.array.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
export default SkillsSelector;
|
export default SkillsSelector;
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import React from "react";
|
import propTypes from "prop-types";
|
||||||
|
|
||||||
import styles from "../style";
|
import styles from "../style";
|
||||||
import TextDivider from "./TextDivider";
|
import TextDivider from "./TextDivider";
|
||||||
|
|
||||||
|
|
||||||
const StepFourJoblisting = ({ handleChange, formData, nextStep, prevStep }) => {
|
const StepFourJoblisting = ({ handleChange, formData, nextStep, prevStep }) => {
|
||||||
return (
|
return (
|
||||||
<div className={`${styles.flexCenter}`}>
|
<div className={`${styles.flexCenter}`}>
|
||||||
@ -120,4 +123,11 @@ const StepFourJoblisting = ({ handleChange, formData, nextStep, prevStep }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StepFourJoblisting.propTypes = {
|
||||||
|
handleChange: propTypes.func,
|
||||||
|
formData: propTypes.object,
|
||||||
|
nextStep: propTypes.func,
|
||||||
|
prevStep: propTypes.func,
|
||||||
|
};
|
||||||
|
|
||||||
export default StepFourJoblisting;
|
export default StepFourJoblisting;
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
import React from "react";
|
|
||||||
import styles from "../style";
|
import styles from "../style";
|
||||||
|
import propTypes from "prop-types";
|
||||||
|
|
||||||
const StepOneJoblisting = ({ nextStep, handleChange, formData }) => {
|
const StepOneJoblisting = ({ nextStep, handleChange, formData }) => {
|
||||||
// Funkcja do obsługi kliknięcia na div i aktualizacji stanu
|
// Funkcja do obsługi kliknięcia na div i aktualizacji stanu
|
||||||
const handleDivClick = (value) => () => {
|
const handleDivClick = (value) => () => {
|
||||||
@ -76,4 +78,10 @@ const StepOneJoblisting = ({ nextStep, handleChange, formData }) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
StepOneJoblisting.propTypes = {
|
||||||
|
nextStep: propTypes.func,
|
||||||
|
handleChange: propTypes.func,
|
||||||
|
formData: propTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
export default StepOneJoblisting;
|
export default StepOneJoblisting;
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import React, { useEffect } from 'react';
|
|
||||||
import DOMPurify from 'dompurify';
|
import DOMPurify from 'dompurify';
|
||||||
import styles from '../style';
|
|
||||||
import TextDivider from './TextDivider';
|
import TextDivider from './TextDivider';
|
||||||
import ListingSmall from './ListingSmall';
|
import ListingSmall from './ListingSmall';
|
||||||
import { IzaacLOGO } from '../assets'
|
import { IzaacLOGO } from '../assets'
|
||||||
|
|
||||||
import SkillsList from './SkillList';
|
import SkillsList from './SkillList';
|
||||||
|
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
const StepThreeJoblisting = ({ formData, prevStep, skills, handleSubmit }) => {
|
const StepThreeJoblisting = ({ formData, prevStep, skills, handleSubmit }) => {
|
||||||
// Funkcja do przetwarzania HTML i dodawania klas
|
// Funkcja do przetwarzania HTML i dodawania klas
|
||||||
const processHTML = (htmlString) => {
|
const processHTML = (htmlString) => {
|
||||||
@ -103,4 +104,11 @@ const StepThreeJoblisting = ({ formData, prevStep, skills, handleSubmit }) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StepThreeJoblisting.propTypes = {
|
||||||
|
formData: PropTypes.object,
|
||||||
|
prevStep: PropTypes.func,
|
||||||
|
skills: PropTypes.array,
|
||||||
|
handleSubmit: PropTypes.func
|
||||||
|
}
|
||||||
|
|
||||||
export default StepThreeJoblisting;
|
export default StepThreeJoblisting;
|
||||||
|
|||||||
@ -1,4 +1,7 @@
|
|||||||
import React, { useState } from 'react'
|
import { useState } from 'react'
|
||||||
|
import propTypes from 'prop-types';
|
||||||
|
|
||||||
|
import { categories, experience_levels } from '../consts';
|
||||||
import styles from '../style'
|
import styles from '../style'
|
||||||
import { CKEditor } from '@ckeditor/ckeditor5-react';
|
import { CKEditor } from '@ckeditor/ckeditor5-react';
|
||||||
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
|
import ClassicEditor from '@ckeditor/ckeditor5-build-classic';
|
||||||
@ -7,8 +10,6 @@ import SkillsSelector from './SkillsSelector';
|
|||||||
import Salary from './Salary';
|
import Salary from './Salary';
|
||||||
import { placeholderImage } from '../assets';
|
import { placeholderImage } from '../assets';
|
||||||
|
|
||||||
import { categories, experience_levels } from '../consts';
|
|
||||||
|
|
||||||
const StepTwoJoblisting = ({ nextStep, prevStep, handleChange, formData, setFormData, removeFields, skills }) => {
|
const StepTwoJoblisting = ({ nextStep, prevStep, handleChange, formData, setFormData, removeFields, skills }) => {
|
||||||
const [editorData, setEditorData] = useState('');
|
const [editorData, setEditorData] = useState('');
|
||||||
const [imageSrc, setImageSrc] = useState(placeholderImage);
|
const [imageSrc, setImageSrc] = useState(placeholderImage);
|
||||||
@ -230,4 +231,14 @@ const StepTwoJoblisting = ({ nextStep, prevStep, handleChange, formData, setForm
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StepTwoJoblisting.propTypes = {
|
||||||
|
nextStep: propTypes.func,
|
||||||
|
prevStep: propTypes.func,
|
||||||
|
handleChange: propTypes.func,
|
||||||
|
formData: propTypes.object,
|
||||||
|
setFormData: propTypes.func,
|
||||||
|
removeFields: propTypes.func,
|
||||||
|
skills: propTypes.array
|
||||||
|
}
|
||||||
|
|
||||||
export default StepTwoJoblisting
|
export default StepTwoJoblisting
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
|
||||||
import TextDivider from './TextDivider'
|
import TextDivider from './TextDivider'
|
||||||
|
|
||||||
const Success = () => {
|
const Success = () => {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
const TextDivider = ({text }) => {
|
import propTypes from 'prop-types'
|
||||||
|
|
||||||
|
const TextDivider = ({ text }) => {
|
||||||
return (
|
return (
|
||||||
<div className='flex items-center justify-center mt-4 mb-6'>
|
<div className='flex items-center justify-center mt-4 mb-6'>
|
||||||
<div className='h-0.5 bg-black w-[14rem] opacity-30'></div>
|
<div className='h-0.5 bg-black w-[14rem] opacity-30'></div>
|
||||||
@ -13,4 +14,7 @@ const TextDivider = ({text }) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TextDivider.propTypes = {
|
||||||
|
text: propTypes.string
|
||||||
|
}
|
||||||
export default TextDivider
|
export default TextDivider
|
||||||
|
|||||||
@ -2,13 +2,15 @@ import React from "react";
|
|||||||
|
|
||||||
import { useState, useEffect } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import ListingSmall from "./ListingSmall";
|
import ListingSmall from "./ListingSmall";
|
||||||
import SkillRender from "./SkillRender";
|
// import SkillRender from "./SkillRender";
|
||||||
import Search from "./Search";
|
// import Search from "./Search";
|
||||||
import Filter from "./Filter";
|
import Filter from "./Filter";
|
||||||
import Category from "./Category";
|
// import Category from "./Category";
|
||||||
import JobOfferContent from "./JobOfferContent";
|
import JobOfferContent from "./JobOfferContent";
|
||||||
import { categories } from "../consts";
|
import { categories } from "../consts";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { Link, useParams } from "react-router-dom";
|
||||||
|
|
||||||
|
|
||||||
function renderCircles(level) {
|
function renderCircles(level) {
|
||||||
let numberOfFilledCircles;
|
let numberOfFilledCircles;
|
||||||
@ -44,11 +46,17 @@ function renderCircles(level) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const WorkApp = () => {
|
const WorkApp = () => {
|
||||||
|
let { id } = useParams();
|
||||||
|
|
||||||
const [isDetailsVisible, setIsDetailsVisible] = useState(false);
|
const [isDetailsVisible, setIsDetailsVisible] = useState(false);
|
||||||
// Czy szczegóły są widoczne
|
// Czy szczegóły są widoczne
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
|
||||||
// Funkcja pobierająca dane z API
|
// useEffect(() => {
|
||||||
|
// if (!isOpen) {
|
||||||
|
// setSearchQuery({ name: "", localization: "", min_salary: "", max_salary: "" });
|
||||||
|
// }}, [isOpen]);
|
||||||
|
|
||||||
const [ogloszenia, setOgloszenia] = useState([]);
|
const [ogloszenia, setOgloszenia] = useState([]);
|
||||||
|
|
||||||
const [skills, setSkills] = useState([]);
|
const [skills, setSkills] = useState([]);
|
||||||
@ -64,12 +72,15 @@ const WorkApp = () => {
|
|||||||
// console.log(data);
|
// console.log(data);
|
||||||
if (data.length > 0) {
|
if (data.length > 0) {
|
||||||
setSelectedOgloszenie(data[0]);
|
setSelectedOgloszenie(data[0]);
|
||||||
// console.log(data[0])
|
console.log(data[0])
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
if (id === undefined) {
|
||||||
|
id = ogloszenia[0]?.id;
|
||||||
|
}
|
||||||
|
|
||||||
const getSkills = async () => {
|
const getSkills = async () => {
|
||||||
try {
|
try {
|
||||||
@ -86,26 +97,27 @@ const WorkApp = () => {
|
|||||||
|
|
||||||
|
|
||||||
const [searchQuery, setSearchQuery] = useState({});
|
const [searchQuery, setSearchQuery] = useState({});
|
||||||
|
const clearSearchQuery = () => {
|
||||||
|
setSearchQuery({});
|
||||||
|
};
|
||||||
|
|
||||||
const [selectedOgloszenie, setSelectedOgloszenie] = useState(ogloszenia[0]);
|
const [selectedOgloszenie, setSelectedOgloszenie] = useState(ogloszenia[0]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getOgloszenia();
|
getOgloszenia();
|
||||||
getSkills();
|
getSkills();
|
||||||
|
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.title = `Izaac - ${selectedOgloszenie?.name}`;
|
||||||
|
}, [selectedOgloszenie?.name]);
|
||||||
|
|
||||||
const handleOgloszenieClick = (ogloszenie) => {
|
const handleOgloszenieClick = (ogloszenie) => {
|
||||||
setSelectedOgloszenie(ogloszenie);
|
setSelectedOgloszenie(ogloszenie);
|
||||||
setIsDetailsVisible(true); // Pokaż szczegóły na urządzeniach mobilnych
|
setIsDetailsVisible(true); // Pokaż szczegóły na urządzeniach mobilnych
|
||||||
};
|
};
|
||||||
const prevSlide = () => {
|
|
||||||
setCurrentSlide(
|
|
||||||
(prevSlide) => (prevSlide - 1 + categories.length) % categories.length
|
|
||||||
);
|
|
||||||
};
|
|
||||||
const nextSlide = () => {
|
|
||||||
setCurrentSlide((prevSlide) => (prevSlide + 1) % categories.length);
|
|
||||||
};
|
|
||||||
const [currentSlide, setCurrentSlide] = React.useState(0);
|
|
||||||
// Funkcja do powrotu do listy ogłoszeń
|
// Funkcja do powrotu do listy ogłoszeń
|
||||||
const handleBackToList = () => {
|
const handleBackToList = () => {
|
||||||
setIsDetailsVisible(false);
|
setIsDetailsVisible(false);
|
||||||
@ -125,53 +137,50 @@ const WorkApp = () => {
|
|||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className=" mx-auto bg-white w-full">
|
<section className={`bg-white w-full`}>
|
||||||
<div className="flex-grow h-5/6 grid grid-cols-10">
|
<div className="h-[88vh] flex flex-row sm:px-12">
|
||||||
<div className="px-3 flex col-span-11 sm:flex-wrap flex-shrink-0 items-center place-content-center">
|
|
||||||
<button onClick={prevSlide} className="lg:hidden mx-6 font-semibold place-self-start self-center leading-5">
|
|
||||||
Poprzednia <br/> kategoria
|
|
||||||
</button>
|
|
||||||
{categories.map((category, index) => (
|
|
||||||
<div
|
|
||||||
key={index}
|
|
||||||
className={`lg:block ${
|
|
||||||
index === currentSlide ? "block" : "hidden"
|
|
||||||
} lg:flex flex-grow lg:flex-none flex-basis-0"`}
|
|
||||||
>
|
|
||||||
<Category
|
|
||||||
name={category.name}
|
|
||||||
last={index === categories.length - 1}
|
|
||||||
small={isSmallViewport}
|
|
||||||
func={() => { getOgloszenia({ category: category.id }); }}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
<button onClick={nextSlide} className="lg:hidden font-semibold leading-5 place-self-end self-center mr-6">
|
|
||||||
Następna <br/> kategoria
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div
|
<div
|
||||||
className={`static rounded-xl col-span-11 sm:col-span-4 bg-gray-100 overflow-y-auto px-2 my-4 mx-2 sm:h-[84vh] h-[84vh] ${
|
className={`relative bg-gray-100 w-full sm:w-[40%]
|
||||||
|
${isOpen ? 'h-[100vh] overflow-y-hidden' : 'sm:overflow-y-auto'}
|
||||||
|
sm:h-[89vh] ${
|
||||||
isDetailsVisible ? "hidden sm:block" : "block"
|
isDetailsVisible ? "hidden sm:block" : "block"
|
||||||
}`}
|
} `}
|
||||||
>
|
>
|
||||||
<div className="z-10 sticky top-0 col-span-11 sm:cols-span-4 h-24 bg-slate-300 flex items-center place-content-center mb-2">
|
<div className="z-10 sticky top-[70px] sm:top-0 w-[100vw] sm:w-full">
|
||||||
<h1 className="text-center text-3xl font-poppins font-semibold text-slate-800 py-4 mx-6">
|
<div className="z-10 w-full fixed sm:sticky top-[4.4rem] sm:top-0 min-h-fit bg-slate-300 flex items-center place-content-center py-1 sm:py-2">
|
||||||
|
<h1 className="text-center text-xl sm:text-2xl font-poppins font-semibold text-slate-800 py-2 mx-6">
|
||||||
Oferty pracy
|
Oferty pracy
|
||||||
</h1>
|
</h1>
|
||||||
<button
|
<button
|
||||||
className="block font-poppins text-white font-semibold
|
className="block font-poppins text-white font-semibold
|
||||||
bg-gray-500 px-4 py-2 mx-6 rounded-md"
|
bg-gray-500 px-4 py-2 mx-6 rounded-md hover:bg-gray-600 duration-100"
|
||||||
onClick={() => setIsOpen(!isOpen)}
|
onClick={() => setIsOpen(!isOpen)}
|
||||||
>
|
>
|
||||||
Pokaż filtry
|
|
||||||
|
{!isOpen ? 'Pokaż filtry' : 'Ukryj filtry'}
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div className="z-10 sticky top-24 col-span-11 sm:cols-span-4 bg-slate-300 mb-2">
|
<div className={`z-10 absolute top-[3rem] sm:top-16 w-[100vw] sm:w-full`}>
|
||||||
{isOpen && <Filter isOpen={isOpen} />}
|
<Filter isOpen={isOpen}
|
||||||
|
searchQuery={searchQuery || {}}
|
||||||
|
setSearchQuery={setSearchQuery}
|
||||||
|
categories={categories}
|
||||||
|
clearSearchQuery={clearSearchQuery}
|
||||||
|
onClick={()=> {getOgloszenia(searchQuery)
|
||||||
|
setIsOpen(!isOpen)
|
||||||
|
}}/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className={`sm:mt-2 mr-2 mt-[8rem] noblur ${!isOpen ? '' : 'blur'}`}
|
||||||
|
|
||||||
|
>
|
||||||
{ogloszenia.map((ogloszenie, index) => (
|
{ogloszenia.map((ogloszenie, index) => (
|
||||||
|
<Link
|
||||||
|
key={ogloszenie.id}
|
||||||
|
to={`/work/joboffers/${ogloszenie.id}`} >
|
||||||
<ListingSmall
|
<ListingSmall
|
||||||
key={ogloszenie.id}
|
key={ogloszenie.id}
|
||||||
name={ogloszenie.name}
|
name={ogloszenie.name}
|
||||||
@ -181,14 +190,18 @@ const WorkApp = () => {
|
|||||||
require_salary={ogloszenie.require_salary}
|
require_salary={ogloszenie.require_salary}
|
||||||
image={ogloszenie.image}
|
image={ogloszenie.image}
|
||||||
index={index}
|
index={index}
|
||||||
onClick={() => handleOgloszenieClick(ogloszenie)}
|
onClick={() => {handleOgloszenieClick(ogloszenie)}}
|
||||||
|
selected={selectedOgloszenie?.id === ogloszenie.id}
|
||||||
|
blur={isOpen ? 'blur' : ''}
|
||||||
/>
|
/>
|
||||||
|
</Link>
|
||||||
))}
|
))}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className={`sm:col-span-6 col-span-11 bg-gray-100 sm:h-[84vh] h-[84vh] overflow-y-auto p-4 my-4 ${
|
className={`absolute sm:relative w-full sm:w-[60%] bg-gray-100 sm:h-[89vh] h-[100vh] top-16 sm:top-0 -left-4 right-0 overflow-y-auto p-4 mx-4 blur-transition ${
|
||||||
isDetailsVisible ? "block" : "hidden sm:block"
|
isDetailsVisible ? "block" : "hidden sm:block"
|
||||||
}`}
|
} noblur ${isOpen ? 'blur' : ''}`}
|
||||||
>
|
>
|
||||||
{isDetailsVisible && (
|
{isDetailsVisible && (
|
||||||
<div className="grid grid-cols-6">
|
<div className="grid grid-cols-6">
|
||||||
@ -202,19 +215,8 @@ const WorkApp = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{selectedOgloszenie && (
|
{selectedOgloszenie && (
|
||||||
<JobOfferContent id={selectedOgloszenie.id} skills={skills} />
|
<JobOfferContent id={id} skills={skills} />
|
||||||
)}
|
)}
|
||||||
{/* <div className='grid sm:grid-cols-2 md:grid-cols-5 grid-cols-2'>
|
|
||||||
{Object.entries(selectedOgloszenie.neededSkills).map(([skill, level]) => (
|
|
||||||
<SkillRender
|
|
||||||
skill={skill}
|
|
||||||
level={level}
|
|
||||||
/>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
<div className='text-slate-800 font-medium mt-4'>
|
|
||||||
{selectedOgloszenie.tresc}
|
|
||||||
</div> */}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|||||||
@ -169,12 +169,12 @@ export const linki = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "2",
|
"id": "2",
|
||||||
"name": "work/postings",
|
"name": "work/joboffers",
|
||||||
"title": "Ogłoszenia",
|
"title": "Ogłoszenia",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"id": "3",
|
"id": "3",
|
||||||
"name": "work/jobposting",
|
"name": "work/addjoboffer",
|
||||||
"title": "Dodaj ogłoszenie",
|
"title": "Dodaj ogłoszenie",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
116
src/index.css
116
src/index.css
@ -22,6 +22,27 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* @layer components {
|
||||||
|
.no-spin-buttons::-webkit-inner-spin-button,
|
||||||
|
.no-spin-buttons::-webkit-outer-spin-button {
|
||||||
|
@apply -webkit-appearance-none margin-0;
|
||||||
|
}
|
||||||
|
.no-spin-buttons {
|
||||||
|
@apply -moz-appearance-textfield;
|
||||||
|
}
|
||||||
|
} */
|
||||||
|
|
||||||
|
input[type="number"]::-webkit-inner-spin-button,
|
||||||
|
input[type="number"]::-webkit-outer-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dla Firefox */
|
||||||
|
input[type="number"] {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
|
||||||
@tailwind components;
|
@tailwind components;
|
||||||
@tailwind utilities;
|
@tailwind utilities;
|
||||||
|
|
||||||
@ -60,11 +81,43 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Expanded state styles */
|
/* Expanded state styles */
|
||||||
.expanded {
|
.collapsible {
|
||||||
max-height: fit-content; /* Adjust as needed */
|
max-height: 0;
|
||||||
opacity: 1;
|
overflow: hidden;
|
||||||
|
transition-property: all;
|
||||||
|
transition-timing-function: ease-in-out;
|
||||||
|
transition-duration: 0.5s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Styl dla elementu, gdy jest rozwinięty */
|
||||||
|
.collapsible.expanded {
|
||||||
|
max-height: 1000px; /* Przykładowa maksymalna wysokość, może wymagać dostosowania */
|
||||||
|
opacity: 1;
|
||||||
|
transition-property: all;
|
||||||
|
transition-timing-function: ease-in-out;
|
||||||
|
transition-duration: 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.div-transition {
|
||||||
|
transition-property: filter;
|
||||||
|
transition-duration: 1s;
|
||||||
|
transition-timing-function: ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.noblur {
|
||||||
|
filter: blur(0px);
|
||||||
|
transition-property: filter;
|
||||||
|
transition-duration: 0.5s;
|
||||||
|
transition-timing-function: ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blur {
|
||||||
|
filter: blur(5px);
|
||||||
|
transition-property: filter;
|
||||||
|
transition-duration: 0.5s;
|
||||||
|
transition-timing-function: ease-in-out;
|
||||||
|
}
|
||||||
.minus-z-index {
|
.minus-z-index {
|
||||||
z-index: -10;
|
z-index: -10;
|
||||||
}
|
}
|
||||||
@ -109,59 +162,4 @@
|
|||||||
.sidebar-hide {
|
.sidebar-hide {
|
||||||
-webkit-animation: slide-down 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
|
-webkit-animation: slide-down 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
|
||||||
animation: slide-down 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
|
animation: slide-down 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94) both;
|
||||||
}
|
}
|
||||||
|
|
||||||
@-webkit-keyframes slide-top {
|
|
||||||
0% {
|
|
||||||
-webkit-transform: translateX(600px);
|
|
||||||
transform: translateX(600px);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
-webkit-transform: translateX(0);
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes slide-top {
|
|
||||||
0% {
|
|
||||||
-webkit-transform: translateX(600px);
|
|
||||||
transform: translateX(600px);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
-webkit-transform: translateX(0);
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@-webkit-keyframes slide-down {
|
|
||||||
0% {
|
|
||||||
-webkit-transform: translateX(0);
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
-webkit-transform: translateX(600px);
|
|
||||||
transform: translateX(600px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes slide-down {
|
|
||||||
0% {
|
|
||||||
-webkit-transform: translateX(0);
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
100% {
|
|
||||||
-webkit-transform: translateX(600px);
|
|
||||||
transform: translateX(600px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@media (max-width: 768px) {
|
|
||||||
.details-section {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
.list-section {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ -7,7 +7,7 @@ module.exports = {
|
|||||||
colors: {
|
colors: {
|
||||||
primary: "#00040f",
|
primary: "#00040f",
|
||||||
secondary: "#00f6ff",
|
secondary: "#00f6ff",
|
||||||
dimWhite: "rgba(255, 255, 255, 0.7)",
|
dimWhite: "rgba(255, 255, 255, 0.8)",
|
||||||
dimBlue: "rgba(9, 151, 124, 0.1)",
|
dimBlue: "rgba(9, 151, 124, 0.1)",
|
||||||
},
|
},
|
||||||
fontFamily: {
|
fontFamily: {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user