Compare commits

..

6 Commits

Author SHA1 Message Date
Jakub Kaniecki
10103fb1a1 fix merge conflicts and merge develop to master
All checks were successful
continuous-integration/drone/push Build is passing
2024-06-08 19:59:36 +02:00
Jakub Kaniecki
07038e720b cicd
Some checks failed
continuous-integration/drone/pr Build is failing
2024-06-07 19:37:42 +02:00
Jakub Kaniecki
e64435143b zmiana adresu 2024-06-07 19:36:50 +02:00
Jakub K
99e6e227e3 przezutka do nowego kompa 2024-04-28 14:43:08 +02:00
Jakub K
9e63b87ba6 ci/cd 2024-03-27 19:05:00 +01:00
Jakub K
11b1ff68e2 mala zmiana w widoku 2024-03-27 19:04:09 +01:00
9 changed files with 744 additions and 460 deletions

10
eslint.config.js Normal file
View File

@ -0,0 +1,10 @@
import globals from "globals";
import pluginJs from "@eslint/js";
import pluginReactConfig from "eslint-plugin-react/configs/recommended.js";
export default [
{languageOptions: { globals: globals.browser }},
pluginJs.configs.recommended,
pluginReactConfig,
];

811
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -13,22 +13,24 @@
"@ckeditor/ckeditor5-build-classic": "^40.0.0", "@ckeditor/ckeditor5-build-classic": "^40.0.0",
"@ckeditor/ckeditor5-build-multi-root": "^40.0.0", "@ckeditor/ckeditor5-build-multi-root": "^40.0.0",
"@ckeditor/ckeditor5-react": "^6.1.0", "@ckeditor/ckeditor5-react": "^6.1.0",
"axios": "^0.24.0",
"dompurify": "^3.0.6", "dompurify": "^3.0.6",
"react": "^18.2.0", "react": "^18.2.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-router-dom": "^6.18.0", "react-router-dom": "^6.18.0"
"axios": "^0.24.0"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "^9.3.0",
"@tailwindcss/typography": "^0.5.10", "@tailwindcss/typography": "^0.5.10",
"@types/react": "^18.2.15", "@types/react": "^18.2.15",
"@types/react-dom": "^18.2.7", "@types/react-dom": "^18.2.7",
"@vitejs/plugin-react": "^4.0.3", "@vitejs/plugin-react": "^4.0.3",
"autoprefixer": "^10.4.16", "autoprefixer": "^10.4.16",
"eslint": "^8.45.0", "eslint": "^8.57.0",
"eslint-plugin-react": "^7.32.2", "eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"eslint-plugin-react-refresh": "^0.4.3", "eslint-plugin-react-refresh": "^0.4.7",
"globals": "^15.2.0",
"postcss": "^8.4.31", "postcss": "^8.4.31",
"postcss-nesting": "^12.0.1", "postcss-nesting": "^12.0.1",
"tailwindcss": "^3.3.5", "tailwindcss": "^3.3.5",

View File

@ -3,14 +3,14 @@ import React from 'react'
const Category = (props) => { const Category = (props) => {
return ( return (
<div className='flex flex-shrink-0 items-center gap-6 mr-6'> <div className='flex flex-shrink-0 items-center gap-6 mr-6'>
<a className='mx-auto text-center text-l <button onClick={props.func} className='mx-auto text-center text-l
font-poppins font-semibold text-slate-800 font-poppins font-semibold text-slate-800
py-4 hover:scale-125 duration-200' py-4 hover:scale-110 duration-200'
href='' > href='' >
{props.name} {props.name}
</a> </button>
<div className={`w-0.5 h-6 bg-black opacity-10 <div className={`w-0.5 h-6 bg-black opacity-10
${props.last ? 'hidden' : 'block'}`}></div> ${props.small || props.last && !props.small ? 'hidden' : 'block'}`}></div>
</div> </div>
) )
} }

View File

@ -5,7 +5,7 @@ import Search from './Search'
const Filter = (props) => { const Filter = (props) => {
if (!props.isOpen) return null; if (!props.isOpen) return null;
return ( return (
<div className={`sticky top-24 z-20 bg-gray-100 grid grid-cols-2 slide-container my-6 py-5 ${!props.isOpen ? '' : 'expanded'}`}> <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'}`}>
<Search label='Wyszukaj ogłoszenie' <Search label='Wyszukaj ogłoszenie'
placeholder='Wpisz nazwę stanowiska...' /> placeholder='Wpisz nazwę stanowiska...' />
<Search label='Lokalizacja' <Search label='Lokalizacja'

View File

@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
import axios from 'axios'; import axios from 'axios';
import DOMPurify from 'dompurify'; import DOMPurify from 'dompurify';
import SkillRender from './SkillRender'; import SkillRender from './SkillRender';
@ -48,7 +48,7 @@ const JobOfferContent = ({ id, skills }) => {
{jobOffer && ( {jobOffer && (
<> <>
<h1 className="my-4 mx-6 text-3xl font-bold text-slate-800">{jobOffer.name} w {jobOffer.company_name}</h1> <h1 className="my-4 mx-6 text-3xl font-bold text-slate-800">{jobOffer.name} w {jobOffer.company_name}</h1>
<div className="grid grid-cols-2 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 gap-4"> <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-2 lg:grid-cols-3 gap-2 sm:gap-4">
{jobOffer.skill_levels && jobOffer.skill_levels.map((skillLevel) => { {jobOffer.skill_levels && jobOffer.skill_levels.map((skillLevel) => {
const skill = skills.find((s) => s.id === parseInt(skillLevel.skill_id)); const skill = skills.find((s) => s.id === parseInt(skillLevel.skill_id));
return skill ? ( return skill ? (

View File

@ -10,7 +10,7 @@ const Search = (props) => {
<input type="text" <input type="text"
placeholder={props.placeholder} placeholder={props.placeholder}
className="border-2 border-gray-300 className="border-2 border-gray-300
bg-white h-10 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" />
</div> </div>
) )

View File

@ -1,25 +1,26 @@
import React from 'react' 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 axios from "axios";
import axios from 'axios';
function renderCircles(level) { function renderCircles(level) {
let numberOfFilledCircles; let numberOfFilledCircles;
switch (level) { switch (level) {
case 'Podstawowy': case "Podstawowy":
numberOfFilledCircles = 1; numberOfFilledCircles = 1;
break; break;
case 'Zaawansowany': case "Zaawansowany":
numberOfFilledCircles = 3; numberOfFilledCircles = 3;
break; break;
case 'Ekspert': case "Ekspert":
numberOfFilledCircles = 5; numberOfFilledCircles = 5;
break; break;
default: default:
@ -31,12 +32,16 @@ function renderCircles(level) {
{[...Array(5)].map((_, index) => ( {[...Array(5)].map((_, index) => (
<div <div
key={index} key={index}
className={`inline-block w-3.5 h-3.5 mr-1 rounded-full ${index < numberOfFilledCircles ? 'bg-red-300 hover:bg-red-700' : 'bg-gray-500 hover:bg-gray-600'}`} className={`inline-block w-3.5 h-3.5 mr-1 rounded-full ${
index < numberOfFilledCircles
? "bg-red-300 hover:bg-red-700"
: "bg-gray-500 hover:bg-gray-600"
}`}
/> />
))} ))}
</> </>
); );
}; }
const WorkApp = () => { const WorkApp = () => {
const [isDetailsVisible, setIsDetailsVisible] = useState(false); const [isDetailsVisible, setIsDetailsVisible] = useState(false);
@ -48,9 +53,12 @@ const WorkApp = () => {
const [skills, setSkills] = useState([]); const [skills, setSkills] = useState([]);
const getOgloszenia = async () => { const getOgloszenia = async (queryParams = {}) => {
try { try {
const response = await axios.get('https://izaac.knck.pl/api/jobposting/joboffers_list/'); const response = await axios.get(
"https://izaac.knck.pl/api/jobposting/joboffers_list/",
{ params: queryParams }
);
const data = response.data; const data = response.data;
setOgloszenia(data); setOgloszenia(data);
// console.log(data); // console.log(data);
@ -65,7 +73,9 @@ const WorkApp = () => {
const getSkills = async () => { const getSkills = async () => {
try { try {
const response = await axios.get(`https://izaac.knck.pl/api/jobposting/skills/`); const response = await axios.get(
`https://izaac.knck.pl/api/jobposting/skills/`
);
const data = response.data; const data = response.data;
setSkills(data); setSkills(data);
console.log(data); console.log(data);
@ -74,9 +84,9 @@ const WorkApp = () => {
} }
}; };
const [searchQuery, setSearchQuery] = useState('');
const [selectedOgloszenie, setSelectedOgloszenie] = useState(ogloszenia[0]);
const [searchQuery, setSearchQuery] = useState({});
const [selectedOgloszenie, setSelectedOgloszenie] = useState(ogloszenia[0]);
useEffect(() => { useEffect(() => {
getOgloszenia(); getOgloszenia();
@ -87,43 +97,79 @@ const WorkApp = () => {
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);
}; };
const [isSmallViewport, setIsSmallViewport] = React.useState(window.innerWidth <= 1025);
React.useEffect(() => {
const handleResize = () => {
setIsSmallViewport(window.innerWidth <= 1025);
};
window.addEventListener('resize', handleResize);
// Clean up the event listener when the component unmounts
return () => {
window.removeEventListener('resize', handleResize);
};
}, []);
return ( return (
<section className=' mx-auto bg-white w-full'> <section className=" mx-auto bg-white w-full">
<div className="flex-grow h-5/6 grid grid-cols-10">
<div className='flex-grow h-5/6 grid grid-cols-10'> <div className="px-3 flex col-span-11 sm:flex-wrap flex-shrink-0 items-center place-content-center">
<div className='px-3 col-span-11 flex flex-wrap 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>
<Category name='Budownictwo' /> {categories.map((category, index) => (
<Category name='Elektryk' /> <div
<Category name='Okretownictwo' /> key={index}
<Category name='Energetyka' /> className={`lg:block ${
<Category name='Lorem Ipsum' /> index === currentSlide ? "block" : "hidden"
<Category name='IT'/> } lg:flex flex-grow lg:flex-none flex-basis-0"`}
<Category name='Budownictwo' >
last={true} /> <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] ${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={`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] ${
<h1 className='text-center text-3xl font-poppins font-semibold text-slate-800 py-4 mx-6'>Oferty pracy</h1> 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">
<h1 className="text-center text-3xl font-poppins font-semibold text-slate-800 py-4 mx-6">
Oferty pracy
</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"
onClick={() => setIsOpen(!isOpen)} onClick={() => setIsOpen(!isOpen)}
>Pokaż filtry</button> >
Pokaż filtry
</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 sticky top-24 col-span-11 sm:cols-span-4 bg-slate-300 mb-2">
{isOpen && (<Filter isOpen={isOpen}/>)} {isOpen && <Filter isOpen={isOpen} />}
</div> </div>
{ogloszenia.map((ogloszenie, index) => ( {ogloszenia.map((ogloszenie, index) => (
<ListingSmall <ListingSmall
@ -139,9 +185,13 @@ const WorkApp = () => {
/> />
))} ))}
</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 ${isDetailsVisible ? 'block' : 'hidden sm:block'}`}> <div
className={`sm:col-span-6 col-span-11 bg-gray-100 sm:h-[84vh] h-[84vh] overflow-y-auto p-4 my-4 ${
isDetailsVisible ? "block" : "hidden sm:block"
}`}
>
{isDetailsVisible && ( {isDetailsVisible && (
<div className='grid grid-cols-6'> <div className="grid grid-cols-6">
<button <button
onClick={handleBackToList} onClick={handleBackToList}
className="sm:hidden block font-poppins text-white font-semibold bg-gray-500 px-4 py-2 rounded-md mx-4 col-span-4 col-start-2" className="sm:hidden block font-poppins text-white font-semibold bg-gray-500 px-4 py-2 rounded-md mx-4 col-span-4 col-start-2"
@ -151,12 +201,9 @@ const WorkApp = () => {
</div> </div>
)} )}
{selectedOgloszenie {selectedOgloszenie && (
&& <JobOfferContent id={selectedOgloszenie.id} skills={skills} />
<JobOfferContent )}
id={selectedOgloszenie.id}
skills={skills}
/>}
{/* <div className='grid sm:grid-cols-2 md:grid-cols-5 grid-cols-2'> {/* <div className='grid sm:grid-cols-2 md:grid-cols-5 grid-cols-2'>
{Object.entries(selectedOgloszenie.neededSkills).map(([skill, level]) => ( {Object.entries(selectedOgloszenie.neededSkills).map(([skill, level]) => (
<SkillRender <SkillRender
@ -171,8 +218,8 @@ const WorkApp = () => {
</div> </div>
</div> </div>
</section> </section>
) );
} };
export default WorkApp export default WorkApp;
export { renderCircles } export { renderCircles };

View File

@ -9,7 +9,7 @@ export default defineConfig({
server: { server: {
proxy: { proxy: {
'/api': { '/api': {
target: 'http://izaac.izaac.pl', target: 'https://izaac.knck.pl',
changeOrigin: false, changeOrigin: false,
secure: false, // Ustaw na true jeśli łączysz się przez HTTPS secure: false, // Ustaw na true jeśli łączysz się przez HTTPS
// Jeśli twoje połączenie HTTPS wymaga niestandardowego certyfikatu: // Jeśli twoje połączenie HTTPS wymaga niestandardowego certyfikatu: