misc fixes, new features

This commit is contained in:
Jakub K 2024-02-13 21:19:37 +01:00
parent 88adb39b19
commit a5f58d1bdb
9 changed files with 192 additions and 137 deletions

View File

@ -6,8 +6,8 @@ import StepFourJoblisting from './StepFourJoblisting'
const AddJobListing = () => {
const [currentStep, setCurrentStep] = useState(1)
const [formData, setFormData] = useState({
'postingOption': 'Opcja 2',
'requireSalary': true
'posting_option': 'S',
'requiresalary': true
})
const nextStep = () => {
setCurrentStep(currentStep + 1);

View File

@ -1,16 +1,19 @@
import React, { useState, useRef, useEffect } from 'react';
import { IzaacLOGO, placeholderImage } from '../assets'
import { placeholderImage } from '../assets';
import axios from 'axios';
const ImageUpload = ({setFormData}) => {
const ImageUpload = ({setFormData, data}) => {
const [imageSrc, setImageSrc] = useState(placeholderImage);
const fileInputRef = useRef(); // Referencja do ukrytego inputu plików
const handleImageChange = (e) => {
const handleImageChange = async (e) => {
const file = e.target.files[0];
if (file) {
const reader = new FileReader();
reader.onload = (e) => {
setImageSrc(e.target.result); // Aktualizujemy stan obrazkiem użytkownika
reader.onload = async (e) => {
// Aktualizujemy stan obrazkiem użytkownika
const uploadedImageData = await uploadImage(file);
};
reader.readAsDataURL(file);
}
@ -20,6 +23,25 @@ const ImageUpload = ({setFormData}) => {
fileInputRef.current.click(); // Programowe kliknięcie na ukrytym inpucie plików
};
const uploadImage = async (imageFile) => {
const formData = new FormData();
formData.append('company_logo', imageFile);
formData.append('company_name', data.company_name)
try {
const response = await axios.post('http://izaac.izaac.pl/api/jobposting/companylogo/', formData, {
headers: {
"Content-Type": 'multipart/form-data'
}
});
console.log(response)
const url = response.data.company_logo
setImageSrc(url)
}
catch (error) {
console.error('Błąd podczas przesyłania obrazka:', e)
}
}
useEffect(() => {
// Aktualizujemy dane w hooku nadrzędnym za każdym razem, gdy zmienia się imageSrc
if (imageSrc !== placeholderImage) {

View File

@ -28,7 +28,10 @@ const NavBar = () => {
{currentLinks.map((nav, index) => (
<li
key={nav.id}
className={`font-popins font-semibold cursor-pointer xs:text-[18px] sm:text-[14px] lg:text-[18px] text-[10px] ${index === linki.length - 1 ? 'mr-7' : 'sm:mr-7 mr-10'} text-slate-900 hover:text-sky-600`}
className={`font-popins font-semibold cursor-pointer
xs:text-[18px] sm:text-[14px] lg:text-[18px] text-[10px]
${index === linki.length - 1 ? 'mr-7' : 'sm:mr-7 mr-10'}
text-slate-900 hover:text-sky-600`}
>
<Link to={`/${nav.name}`}>{nav.title}</Link>
</li>
@ -50,12 +53,18 @@ const NavBar = () => {
alt="menu"
className='w-[28px] h-[28px] object-contain'
onClick={() => setToggle((prev) => !prev)}/>
<div className={`${toggle ? 'sidebar-show' : 'hidden'} p-6 bg-white absolute top-20 right-0 mx-4 my-2 min-w-[140px] rounded-xl border-4 border-slate-200 z-20`}>
<ul className='list-none flex flex-col justify-end items-center flex-1'>
<div className={`${toggle ? 'sidebar-show' : 'hidden'} p-6
bg-white absolute top-20 right-0 mx-4 my-2 min-w-[140px]
rounded-xl border-4 border-slate-200 z-20`}>
<ul className='list-none flex flex-col justify-end
items-center flex-1'>
{currentLinks.map((nav, index) =>(
<div
key={nav.id}
className={`w fulltext-center font-popins font-normal cursor-pointer text-[16px] ${index === linki.length - 1 ? 'mb-0' : 'mb-3'} text-slate-800`}
className={`w fulltext-center font-popins font-normal
cursor-pointer text-[16px]
${index === linki.length - 1 ? 'mb-0' : 'mb-3'}
text-slate-800`}
>
<Link to={`/${nav.name}`}>{nav.title}</Link>
</div>

View File

@ -22,7 +22,7 @@ const Salary = ({handleChange, formData, removeFields, setFormData}) => {
};
useEffect(() => {
setFormData({...formData, 'requireSalary': requireSalary});
setFormData({...formData, 'requiresalary': requireSalary});
}, [requireSalary]);
const [minBigger, setMinBigger] = useState(true);
@ -46,11 +46,11 @@ const Salary = ({handleChange, formData, removeFields, setFormData}) => {
useEffect(() => {
})
useEffect( () =>{
if (formData.requireSalary === false) {
removeFields(['minSalary', 'maxSalary']);
setRequireSalary(formData.requireSalary)
if (formData.requiresalary === false) {
removeFields(['minsalary', 'maxsalary']);
setRequireSalary(formData.requiresalary)
}
}, [formData.requireSalary])
}, [formData.requiresalary])
return (
@ -60,7 +60,7 @@ const Salary = ({handleChange, formData, removeFields, setFormData}) => {
className='ml-6'
type="checkbox"
checked={!requireSalary}
name="requireSalary"
name="requiresalary"
onChange={handleRequireSalary}
id="" />
<span className='font-poppins font-semibold text-slate-700 text-center text-[14px] mt-1 mb-2'> Nie chce podawać wysokości wynagrodzenia</span>
@ -70,10 +70,10 @@ const Salary = ({handleChange, formData, removeFields, setFormData}) => {
<p className='ml-5 font-poppins font-semibold text-slate-700 text-center text-[14px] mt-1 mb-2'>Min. wynagrodzenie</p>
<input
disabled={!requireSalary}
name='minSalary'
value={formData['minSalary'] || '' }
name='minsalary'
value={formData['minsalary'] || '' }
onChange={handleChange('minSalary')}
onChange={handleChange('minsalary')}
type='number'
className={`h-12 border-2 rounded-xl px-5 mx-4 w-full ${!requireSalary ? 'bg-slate-200' : ''}`}/>
{minBigger && (
@ -86,9 +86,9 @@ const Salary = ({handleChange, formData, removeFields, setFormData}) => {
<p className='ml-5 font-poppins font-semibold text-slate-700 text-center text-[14px] mt-1 mb-2'>Maks. wynagrodzenie</p>
<input
disabled={!requireSalary}
value={formData['maxSalary'] || '' }
value={formData['maxsalary'] || '' }
name="maxSalary"
onChange={handleChange('maxSalary')}
onChange={handleChange('maxsalary')}
type='number'
className={`h-12 border-2 rounded-xl px-5 mx-4 w-full ${!requireSalary ? 'bg-slate-200' : ''} `}/></div>

View File

@ -1,37 +1,25 @@
import React from 'react';
const levels = ['Nice to have','Podstawowy', 'Średnio zaawansowany', 'Zaawansowany', 'Ekspert'];
const levelMappings = {
'N': 'Nice to have',
'B': 'Podstawowy',
'M': 'Średnio zaawansowany',
'A': 'Zaawansowany',
'E': 'Ekspert',
};
function renderCircles(level, handleCircleClick) {
let numberOfFilledCircles;
switch (level) {
case 'Nice to have':
numberOfFilledCircles = 1;
break;
case 'Podstawowy':
numberOfFilledCircles = 2;
break;
case 'Średnio zaawansowany':
numberOfFilledCircles = 3;
break
case 'Zaawansowany':
numberOfFilledCircles = 4;
break;
case 'Ekspert':
numberOfFilledCircles = 5;
break;
default:
numberOfFilledCircles = 1;
}
function renderCircles(letter, handleCircleClick) {
const level = levelMappings[letter];
const numberOfFilledCircles = Object.keys(levelMappings).indexOf(letter) + 1;
return (
<>
{[...Array(5)].map((_, index) => (
<div
key={index}
onClick={() => handleCircleClick(index)}
className={`justify-self-center w-3.5 h-3.5 rounded-full ${index < numberOfFilledCircles ? 'bg-red-300 hover:bg-red-700' : 'bg-gray-500 hover:bg-gray-600'}`}
onClick={() => handleCircleClick(Object.keys(levelMappings)[index])}
className={`justify-self-center w-3.5 h-3.5 rounded-full
${index < numberOfFilledCircles ? 'bg-red-300 hover:bg-red-700' : 'bg-gray-500 hover:bg-gray-600'}`}
/>
))}
</>
@ -39,10 +27,10 @@ function renderCircles(level, handleCircleClick) {
};
const SelectedSkill = ({ skill, level, onLevelChange, removeSkillFromList, formData }) => {
const SelectedSkill = ({ skill, letter, onLevelChange, removeSkillFromList, formData }) => {
const handleCircleClick = (levelIndex) => {
const level = levels[levelIndex];
onLevelChange(skill, level);
const letter = Object.keys(levelMappings)[levelIndex];
onLevelChange(skill, levelIndex);
};
return (
<div className="skill-block">
@ -53,9 +41,9 @@ const SelectedSkill = ({ skill, level, onLevelChange, removeSkillFromList, formD
</button>
<div className='h-0.5 w-full bg-dimWhite opacity-60 mt-1'></div>
<div className='grid grid-cols-5 mt-2'>
{renderCircles(level, handleCircleClick)}
{renderCircles(letter, handleCircleClick)}
</div>
<p className='font-poppins font-semibold text-slate-700 text-center text-[12px] mt-1'>{level}</p>
<p className='font-poppins font-semibold text-slate-700 text-center text-[12px] mt-1'>{levelMappings[letter]}</p>
</div>
</div>

View File

@ -31,7 +31,6 @@ const initialSkillsList = [
'Technologia nanomateriałów',
'Projektowanie systemów wbudowanych',
'Inżynieria bezpieczeństwa',
// ... więcej umiejętności ...
];
const SkillsSelector = ({formData, setFormData}) => {
@ -56,7 +55,7 @@ const SkillsSelector = ({formData, setFormData}) => {
};
setSkillLevels(prevLevels => ({
...prevLevels,
[skill]: 'Nice to have' // lub inny domyślny poziom
[skill]: 'N' // lub inny domyślny poziom
}));
setInputValue('');
setSuggestions([]);
@ -131,7 +130,7 @@ const SkillsSelector = ({formData, setFormData}) => {
<SelectedSkill
key={skill}
skill={skill}
level={skillLevels[skill] || 'Nice to have'} // Domyślny poziom, jeśli nie ustawiony
letter={skillLevels[skill] || 'N'} // Domyślny poziom, jeśli nie ustawiony
onLevelChange={handleLevelChange}
removeSkillFromList={removeSkillFromList}
/>

View File

@ -1,68 +1,79 @@
import React from 'react'
import styles from '../style'
import React from "react";
import styles from "../style";
const StepOneJoblisting = ({ nextStep, handleChange, formData }) => {
// Funkcja do obsługi kliknięcia na div i aktualizacji stanu
const handleDivClick = (value) => () => {
handleChange('postingOption')({ target: { value: value } });
};
// Funkcja do obsługi kliknięcia na div i aktualizacji stanu
const handleDivClick = (value) => () => {
handleChange("posting_option")({ target: { value: value } });
};
const activeStyle = "h-[500px] w-64 border-4 rounded-xl border-stone-200 bg-gray-200 div-transition scale-125";
const inactiveStyle = "h-[500px] w-64 rounded-xl bg-gray-200 border-gray-200 div-transition cursor-pointer hover:bg-gray-300"; // Dodaj tę samą klasę przejścia tutaj
const activeStyle =
"h-[500px] w-64 border-4 rounded-xl border-stone-200 bg-gray-200 div-transition scale-125";
const inactiveStyle =
"h-[500px] w-64 rounded-xl bg-gray-200 border-gray-200 div-transition cursor-pointer hover:bg-gray-300";
return (
<>
<div
className={` grid grid-cols-1 ${styles.paddingX} pb-8 pt-8 gap-1 h-full`}
>
<h1 className={`${styles.heading1} text-center`}>
Zacznij dodawać ogłoszenie z izaac.pl
</h1>
<p className={`${styles.paragraph} text-center`}>
Wybierz pakiet najlepiej odpowiadający Twoim potrzebom
</p>
</div>
<div className={` ${styles.flexStart} ${styles.paddingX} gap-16 mt-20`}>
{/* Przykładowe divy jako przyciski wyboru */}
return (
<form>
<div className={` grid grid-cols-1 ${styles.paddingX} pb-8 pt-8 gap-1 h-full`}>
<h1 className={`${styles.heading1} text-center`}>Zacznij dodawać ogłoszenie z izaac.pl</h1>
<p className={`${styles.paragraph} text-center`}>Wybierz pakiet najlepiej odpowiadający Twoim potrzebom</p>
<div
className={
formData.posting_option === "M" ? activeStyle : inactiveStyle
}
onClick={handleDivClick("M")}
>
<p className={`${styles.paragraph} text-center mt-4`}>Starter</p>
</div>
<div className="h-[400px] w-0.5 bg-gray-300"></div>
<div
className={
formData.posting_option === "S" ? activeStyle : inactiveStyle
}
onClick={handleDivClick("S")}
>
<p className={`${styles.paragraph} text-center mt-4`}>Standard</p>
<div className="mt-6">
<p className={`${styles.paragraph} text-center`}>
najczęsciej wybierany
</p>
</div>
</div>
</div>
<div className={` ${styles.flexStart} ${styles.paddingX} gap-16 mt-20`}>
{/* Przykładowe divy jako przyciski wyboru */}
<div
className={formData.postingOption === 'Opcja 1' ? activeStyle : inactiveStyle}
onClick={handleDivClick('Opcja 1')}
>
<p className={`${styles.paragraph} text-center mt-4`}>Starter</p>
</div>
<div className='h-[400px] w-0.5 bg-gray-300'>
</div>
<div
className={formData.postingOption === 'Opcja 2' ? activeStyle : inactiveStyle}
onClick={handleDivClick('Opcja 2')}
>
<p className={`${styles.paragraph} text-center mt-4`}>Standard</p>
<div className='mt-6'>
<p className={`${styles.paragraph} text-center`}>najczęsciej wybierany</p>
</div>
</div>
<div className='h-[400px] w-0.5 bg-gray-300'>
</div>
<div
className={formData.postingOption === 'Opcja 3' ? activeStyle : inactiveStyle}
onClick={handleDivClick('Opcja 3')}
style={{ cursor: 'pointer' }}
>
<p className={`${styles.paragraph} text-center mt-4`}>Premium</p>
</div>
</div>
<div className='grid pt-32 items-center justify-center'>
<button
type="button"
onClick={nextStep}
className='h-12 w-72 rounded-xl bg-gray-700 font-poppins font-semibold text-[14px] text-white hover:scale-125 duration-300'>Przejdź do następnego kroku &nbsp;&nbsp;<span className='text-[18px]'></span> </button>
<div className='h-12 w-full'></div>
</div>
</form>
);
<div className="h-[400px] w-0.5 bg-gray-300"></div>
<div
className={
formData.posting_option === "P" ? activeStyle : inactiveStyle
}
onClick={handleDivClick("P")}
style={{ cursor: "pointer" }}
>
<p className={`${styles.paragraph} text-center mt-4`}>Premium</p>
</div>
</div>
<div className="grid pt-32 items-center justify-center">
<button
type="button"
onClick={nextStep}
className="h-12 w-72 rounded-xl bg-gray-700
font-poppins font-semibold text-[14px] text-white
hover:scale-125 duration-300"
>
Przejdź do następnego kroku &nbsp;&nbsp;
<span className="text-[18px]"></span>{" "}
</button>
<div className="h-12 w-full"></div>
</div>
</>
);
};
export default StepOneJoblisting
export default StepOneJoblisting;

View File

@ -1,4 +1,4 @@
import React from 'react';
import React, { useEffect } from 'react';
import DOMPurify from 'dompurify';
import styles from '../style';
import TextDivider from './TextDivider';
@ -33,10 +33,18 @@ const StepThreeJoblisting = ({ formData, prevStep }) => {
return <div dangerouslySetInnerHTML={{ __html: cleanAndProcessData(htmlString) }} />;
};
const skillData = Object.entries(formData.skillLevels).map(([skill_id, skill_level]) => {
return {skill_id, skill_level, jobposting_id: null};
});
useEffect(()=>{
console.log(skillData)
}, [skillData,])
return (
<div className='text-center'>
<p className='mt-8 text-[24px] font-poppins font-bold '>
Wybrałeś opcję {formData.postingOption}
Wybrałeś opcję {formData.posting_option}
</p>
<TextDivider text={`Tak będzie wyglądało Twoje ogłoszenie na liście ogłoszeń`} />
@ -54,10 +62,10 @@ const StepThreeJoblisting = ({ formData, prevStep }) => {
>
<p className='col-span-3 text-base text-left tracking-wide'>{cleanAndProcessData(formData.company_name)}</p>
{
formData.requireSalary && (<p className='place-self-end text-[16px] font-semibold tracking-widest text-slate-800'>{cleanAndProcessData(formData.minSalary)} PLN - {cleanAndProcessData(formData.maxSalary)} PLN</p> )
formData.requiresalary && (<p className='place-self-end text-[16px] font-semibold tracking-widest text-slate-800'>{cleanAndProcessData(formData.minsalary)} PLN - {cleanAndProcessData(formData.maxsalary)} PLN</p> )
}
{
!formData.requireSalary && (<p className='place-self-end text-xl text-slate-800'></p> )
!formData.requiresalary && (<p className='place-self-end text-xl text-slate-800'></p> )
}
<p className='col-span-4 text-xl text-left'>{cleanAndProcessData(formData.name)}</p>
</div>

View File

@ -27,8 +27,8 @@ const StepTwoJoblisting = ({ nextStep, prevStep, handleChange, formData, setForm
let newErrors = {};
// Sprawdź każde wymagane pole
if (!formData.jobtitle) {
newErrors.jobtitle = 'To pole jest wymagane';
if (!formData.name) {
newErrors.name = 'To pole jest wymagane';
}
if (!formData.company_name) {
newErrors.company_name = 'To pole jest wymagane';
@ -43,16 +43,16 @@ const StepTwoJoblisting = ({ nextStep, prevStep, handleChange, formData, setForm
if (formData.requireSalary === true)
{
console.log(formData.requireSalary)
if (!formData.minSalary) {
newErrors.minSalary = 'To pole jest wymagane';
if (!formData.minsalary) {
newErrors.minsalary = 'To pole jest wymagane';
}
if (!formData.maxSalary) {
newErrors.maxSalary = 'To pole jest wymagane';
if (!formData.maxsalary) {
newErrors.maxsalary = 'To pole jest wymagane';
}
}
if (!formData.employmentType) {
newErrors.employmentType = 'To pole jest wymagane';
if (!formData.workFromHome) {
newErrors.workFromHome = 'To pole jest wymagane';
}
if (!formData.employmentType) {
newErrors.employmentType = 'To pole jest wymagane';
@ -83,7 +83,8 @@ const StepTwoJoblisting = ({ nextStep, prevStep, handleChange, formData, setForm
<form action="">
<div className='grid mb-4'>
<div className='grid grid-cols-3 items-center'>
<div className={`${styles.paragraph} px-4 py-2`}>Nazwa ogłoszenia<span className={`${styles.paragraph} text-red-700`}>*</span></div>
<div className={`${styles.paragraph} px-4 py-2`}>Nazwa ogłoszenia
<span className={`${styles.paragraph} text-red-700`}>*</span></div>
<input type="text"
name="name"
value={formData['name'] || ''}
@ -91,7 +92,8 @@ const StepTwoJoblisting = ({ nextStep, prevStep, handleChange, formData, setForm
id="name"
onChange={handleChange('name')}
placeholder='Wpisz nazwę stanowiska...'
className={`border-b-2 px-4 my-2 ${styles.paragraph} col-span-2 ${errors.jobtitle ? errorStyleInput : ''}`}/>
className={`border-b-2 px-4 my-2 ${styles.paragraph}
col-span-2 ${errors.jobtitle ? errorStyleInput : ''}`}/>
<div className={`${styles.paragraph} px-4 py-2 `}>Strona internetowa</div>
<input type="text"
@ -101,7 +103,8 @@ const StepTwoJoblisting = ({ nextStep, prevStep, handleChange, formData, setForm
id="webpage"
placeholder='Wpisz adres strony internetowej...'
className={`border-b-2 px-4 my-2 ${styles.paragraph} col-span-2`}/>
<div className={`${styles.paragraph} px-4 py-2 `}>Adres siedziby<span className={`${styles.paragraph} text-red-700`}>*</span></div>
<div className={`${styles.paragraph} px-4 py-2 `}>Adres siedziby
<span className={`${styles.paragraph} text-red-700`}>*</span></div>
<input type="text"
name="localization"
required
@ -110,16 +113,19 @@ const StepTwoJoblisting = ({ nextStep, prevStep, handleChange, formData, setForm
id="localization"
placeholder='Wpisz adres siedziby...'
className={`border-b-2 px-4 my-2 ${styles.paragraph} col-span-2`}/>
<div className={`${styles.paragraph} px-4 py-2 `}>Logo firmy<span className={`${styles.paragraph} text-red-700`}>*</span></div>
<div className={`${styles.paragraph} px-4 py-2 `}>Logo firmy
<span className={`${styles.paragraph} text-red-700`}>*</span></div>
<div className='mt-6 col-span-2'>
<ImageUpload
setFormData={setFormData}
data={formData}
/>
</div>
</div>
</div>
<div className='w-full border-b-2'></div>
<div className={`${styles.paragraph} px-4 py-2`}>Treść ogłoszenia <span className={`${styles.paragraph} text-red-700`}>*</span></div>
<div className={`${styles.paragraph} px-4 py-2`}>Treść ogłoszenia
<span className={`${styles.paragraph} text-red-700`}>*</span></div>
<CKEditor
editor={ClassicEditor}
data={formData['content'] || ''}
@ -149,7 +155,10 @@ const StepTwoJoblisting = ({ nextStep, prevStep, handleChange, formData, setForm
</div>
</div>
<div className='w-full border-b-2'></div>
<div className={`${styles.paragraph} px-4 py-2`}>Wynagrodzenie <span className={`${styles.paragraph} text-red-700`}>*</span></div>
<div className={`${styles.paragraph} px-4 py-2`}>
Wynagrodzenie
<span className={`${styles.paragraph} text-red-700`}>*</span>
</div>
<div className=''>
<Salary
removeFields={removeFields}
@ -162,11 +171,20 @@ const StepTwoJoblisting = ({ nextStep, prevStep, handleChange, formData, setForm
<button
type="button"
onClick={prevStep}
className='h-12 w-72 rounded-xl bg-gray-700 font-poppins font-semibold text-[14px] scale-100 text-white hover:scale-125 duration-300'><span className='text-[18px]'></span>&nbsp;&nbsp;Przejdź do poprzedniego kroku</button>
className='h-12 w-72 rounded-xl bg-gray-700
font-poppins font-semibold text-[14px] scale-100
text-white hover:scale-125 duration-300'>
<span className='text-[18px]'></span>&nbsp;&nbsp;
Przejdź do poprzedniego kroku</button>
<button
type="button"
onClick={handleNextStep}
className='h-12 w-72 rounded-xl bg-gray-700 font-poppins font-semibold text-[14px] scale-100 text-white hover:scale-125 duration-300'>Przejdź do następnego kroku &nbsp;&nbsp;<span className='text-[18px]'></span> </button>
className='h-12 w-72 rounded-xl
bg-gray-700 font-poppins
font-semibold text-[14px] scale-100
text-white hover:scale-125 duration-300'>
Przejdź do następnego kroku &nbsp;&nbsp;
<span className='text-[18px]'></span> </button>
</div>
</form>
</div>