Skip to content

Commit

Permalink
feature: vacancy edit page
Browse files Browse the repository at this point in the history
  • Loading branch information
Regikon committed Dec 17, 2024
1 parent ef00a1a commit 73b2dc6
Show file tree
Hide file tree
Showing 22 changed files with 753 additions and 351 deletions.
8 changes: 4 additions & 4 deletions src/application/action_creators/cv_action_creators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export interface CvFormFields {
const cvFormValidators = new Map(
Object.entries({
positionRu: validateRequired,
positionEn: validatorTrain([validateRequired, validateEnglish]),
positionEn: validatorTrain(validateRequired, validateEnglish),
jobSearchStatus: validateRequired,
description: validateRequired,
workingExperience: validateRequired,
Expand Down Expand Up @@ -111,13 +111,13 @@ function validateCvForm(formFields: CvFormFields): boolean {
isValid,
} as CvFormData,
});
return true;
return isValid;
}

async function createCv(body: CvFormFields) {
const backendOrigin = backendStore.getData().backendOrigin;
if (!validateCvForm(body)) {
return;
throw new TypeError('form is not valid');
}
try {
const newCv = makeCvFromApi(
Expand Down Expand Up @@ -146,7 +146,7 @@ async function createCv(body: CvFormFields) {
async function updateCv(id: number, body: CvFormFields) {
const backendOrigin = backendStore.getData().backendOrigin;
if (!validateCvForm(body)) {
return;
throw new TypeError('form is not valid');
}
try {
const updatedCv = makeCvFromApi(
Expand Down
139 changes: 135 additions & 4 deletions src/application/action_creators/vacancy_action_creators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
UpdateAction,
UpdateActionPayload,
VacancyActions,
VacancyFormSubmitAction,
} from '../stores/vacancy_store/vacancy_actions';
import { makeVacancyFromApi } from '../models/vacancy';
import {
Expand All @@ -17,13 +18,136 @@ import {
getApplicantFavoriteVacancies,
removeVacancyFromFavorites,
resetApplyToVacancy,
createVacancy as apiCreateVacancy,
updateVacancy as apiUpdateVacancy,
} from '@/modules/api/api';
import { assertIfError } from '@/modules/common_utils/asserts/asserts';
import { Application } from '@/modules/api/src/responses/application';
import { makeApplicantFromApi } from '../models/applicant';
import { userStore } from '../stores/user_store/user_store';
import { UserType } from '../models/user-type';
import { Applicant } from '../models/applicant';
import {
validateNumeric,
validateOk,
validateRequired,
validatorTrain,
} from '../validators/validators';
import { FormValue } from '../models/form_value';
import { VacancyFormData, vacancyStore } from '../stores/vacancy_store/vacancy_store';

export interface VacancyFormFields {
position?: string;
salary?: string;
workType?: string;
location?: string;
description?: string;
positionGroup?: string;
}

const vacancyFormValidators = new Map(
Object.entries({
position: validateRequired,
salary: validatorTrain(validateRequired, validateNumeric),
workType: validateRequired,
location: validateRequired,
description: validateRequired,
positionGroup: validateOk,
}),
);

function submitVacancyFields(data: VacancyFormFields) {
const validatedData: VacancyFormData = {};
Object.entries(data).forEach(([key, value]) => {
(validatedData as { [key: string]: FormValue })[key] = vacancyFormValidators.get(key)(value);
});
storeManager.dispatch({
type: VacancyActions.FormSubmit,
payload: validatedData,
} as VacancyFormSubmitAction);
}

function validateVacancyForm(data: VacancyFormFields) {
submitVacancyFields(data);
let isValid = false;
const userData = userStore.getData();
if (userData.userType !== UserType.Employer) {
return false;
}
const { position, salary, workType, location, description } =
vacancyStore.getData().vacancyFormData;
isValid = [position, salary, workType, location, description].every((field) => field.isValid);
storeManager.dispatch({
type: VacancyActions.FormSubmit,
payload: {
isValid,
} as VacancyFormData,
});
return isValid;
}

async function createVacancy(body: VacancyFormFields) {
const backendOrigin = backendStore.getData().backendOrigin;
if (!validateVacancyForm(body)) {
throw new TypeError('Form is not valid');
}
try {
const newVacancy = makeVacancyFromApi(
await apiCreateVacancy(backendOrigin, userStore.getData().csrfToken, {
position: body.position,
salary: Number(body.salary),
location: body.location,
workType: body.workType,
description: body.description,
positionGroup: body.positionGroup,
}),
);
storeManager.dispatch({
type: VacancyActions.Update,
payload: {
vacancy: newVacancy,
loaded: true,
appliers: [],
} as UpdateActionPayload,
} as UpdateAction);
} catch (err) {
assertIfError(err);
console.log(err);
vacancyActionCreators.clearVacancy();
}
}

async function updateVacancy(id: number, body: VacancyFormFields) {
// const backendOrigin = backendStore.getData().backendOrigin;
if (!validateVacancyForm(body)) {
throw new TypeError('Form is not valid');
}
try {
const updatedVacancy = makeVacancyFromApi(
await apiUpdateVacancy(backendStore.getData().backendOrigin, userStore.getData().csrfToken, {
id,
position: body.position,
salary: Number(body.salary),
location: body.location,
workType: body.workType,
description: body.description,
positionGroup: body.positionGroup,
}),
);
const oldVacancy = vacancyStore.getData();
storeManager.dispatch({
type: VacancyActions.Update,
payload: {
vacancy: updatedVacancy,
loaded: true,
appliers: oldVacancy.appliers,
} as UpdateActionPayload,
});
} catch (err) {
assertIfError(err);
console.log(err);
}
}

async function loadVacancy(id: number) {
const backendOrigin = backendStore.getData().backendOrigin;
Expand All @@ -33,7 +157,7 @@ async function loadVacancy(id: number) {
const userData = userStore.getData();
let loadedAppliers: Applicant[];
if (userData.userType === UserType.Employer && userData.id === loadedVacancy.employerId) {
const rawAppliers = await getVacancyAppliers(backendOrigin, id);
const rawAppliers = await getVacancyAppliers(backendOrigin, userData.csrfToken, id);
loadedAppliers = rawAppliers.subscribers.map((apiApplicant) =>
makeApplicantFromApi(apiApplicant),
);
Expand Down Expand Up @@ -181,13 +305,20 @@ function clearVacancy() {
}

export const vacancyActionCreators = {
loadVacancy,
loadApplyStatus,
loadFavoriteStatus,
applyVacancy,
removeApplyVacancy,

clearVacancy,
removeVacancy,

loadFavoriteStatus,
addVacancyToFavorite,
removeVacancyFromFavorite,

submitVacancyFields,

createVacancy,
loadVacancy,
updateVacancy,
removeVacancy,
};
1 change: 1 addition & 0 deletions src/application/components/header/header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export class Header extends Component {
setIsOpen={this.setIsNotifyDropdownOpen}
>
<NotificationList
key="notification-list"
elementClass="header__notification-list"
notifications={notifications}
/>
Expand Down
2 changes: 2 additions & 0 deletions src/application/components/input/input.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export class Input extends Component {
name={this.props.name}
id={this.props.id}
maxlength={this.props.maxlength}
onFocusOut={this.props.onFocusOut}
>
{this.props.value ?? ''}
</textarea>
Expand All @@ -94,6 +95,7 @@ export class Input extends Component {
name={this.props.name}
id={this.props.id}
value={this.props.value}
onFocusOut={this.props.onFocusOut}
>
{(this.props.options as Option[]).map((option) => (
<option value={option.value} key={option.value}>
Expand Down
71 changes: 35 additions & 36 deletions src/application/components/vacancy_article/vacancy_article.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,45 +95,11 @@ export class VacancyArticle extends Component {
</div>
<div className="vacancy-article__divider"></div>
<div className="vacancy-article__description">{vacancy.description}</div>
{this.props.userType === UserType.Applicant && (
<div className="vacancy-article__button-container">
{this.props.isApplied ? (
<button
type="button"
className="vacancy-article__reset-apply-button button button_danger-primary"
onClick={(ev: Event) => this.handleRemoveApply(ev)}
>
Отменить отклик
</button>
) : (
<button
type="button"
className="vacancy-article__apply-button button button_main-primary"
onClick={(ev: Event) => this.handleApply(ev)}
>
Откликнуться
</button>
)}

<a
className="vacancy-article__all-vacancies-button button button_main-secondary"
href={
resolveUrl('profile', null) +
`?id=${vacancy.employerId}&userType=employer&from=vacancyList`
}
>
Все вакансии
</a>
<div className="vacancy-article__created-at">
{`последнее обновление: ${vacancy.createdAt.toLocaleString('ru-RU')}`}
</div>
</div>
)}
{this.props.userType === UserType.Employer && this.props.isOwner && (
{this.props.userType === UserType.Employer && this.props.isOwner ? (
<div className="vacancy-article__button-container">
<a
className="vacancy-article__edit-button button button_main-primary"
href={resolveUrl('editVacancy', null) + `?vacancyId=${vacancy.id}`}
href={resolveUrl('editVacancy', null) + `?id=${vacancy.id}`}
>
Изменить
</a>
Expand All @@ -148,6 +114,39 @@ export class VacancyArticle extends Component {
{`последнее обновление: ${vacancy.updatedAt.toLocaleString('ru-RU')}`}
</div>
</div>
) : (
<div className="vacancy-article__button-container">
{this.props.userType === UserType.Applicant &&
(this.props.isApplied ? (
<button
type="button"
className="vacancy-article__reset-apply-button button button_danger-primary"
onClick={(ev: Event) => this.handleRemoveApply(ev)}
>
Отменить отклик
</button>
) : (
<button
type="button"
className="vacancy-article__apply-button button button_main-primary"
onClick={(ev: Event) => this.handleApply(ev)}
>
Откликнуться
</button>
))}
<a
className="vacancy-article__all-vacancies-button button button_main-secondary"
href={
resolveUrl('profile', null) +
`?id=${vacancy.employerId}&userType=employer&from=vacancyList`
}
>
Все вакансии
</a>
<div className="vacancy-article__created-at">
{`последнее обновление: ${vacancy.createdAt.toLocaleString('ru-RU')}`}
</div>
</div>
)}
</article>
);
Expand Down
9 changes: 3 additions & 6 deletions src/application/pages/cv_edit_page/cv_edit_page.scss
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

.cv-edit-page {
display: flex;
align-self: center;
flex-direction: column;
align-items: stretch;
justify-content: center;
Expand All @@ -17,18 +18,14 @@
border-radius: var(--radius-m);
background-color: var(--color-background-900);

&__description-header {
font-size: var(--text-size-8);
color: var(--color-main-100);
text-align: center;
}

&__form {
display: flex;
flex-direction: column;
}

&__header {
font-size: var(--text-size-8);
color: var(--color-main-100);
text-align: center;
}

Expand Down
Loading

0 comments on commit 73b2dc6

Please sign in to comment.