Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
15 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export const EMPLOYEE_INVITE_ENDPOINT =
"/api/profiles/:profile_id/employee_invite";
export const PROFILE_COMPLETE_ENDPOINT =
"/api/profiles/:profile_id/profile_complete";
export const ADMIN_INVITE_ENDPOINT = "/api/admin_invite";

export const PROFILE_GET_ENDPOINT = "/api/profiles/:profile_id";
export const PROJECT_LIST_ENDPOINT = "/api/profiles/:profile_id/projects";
Expand All @@ -54,6 +55,7 @@ export const UPDATE_EXPERIENCE_ENDPOINT =
export const UPDATE_CERTIFICATE_ENDPOINT =
"/api/profiles/:profile_id/certificates/:certificate_id";
export const UPDATE_SEQUENCE_ENDPOINT = "/api/updateSequence";
export const INTRANET_EMPLOYEE_ENDPOINT = "/api/intranet/employees/:employee_id";

export const DELETE_PROFILE_ENDPOINT = "/api/profiles/:profile_id";
export const DELETE_ACHIEVEMENT_ENDPOINT =
Expand Down
13 changes: 10 additions & 3 deletions src/api/axiosBaseQuery/service.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import axiosInstance from "../../services/axios";

const axiosBaseQuery =
() =>
async ({ url, method, data, params, headers, body }) => {
async ({ url, method, data, params, headers, body, ...rest }) => {
try {
const result = await axiosInstance({
url: url,
Expand All @@ -11,10 +11,17 @@ const axiosBaseQuery =
params,
headers,
body,
...rest,
});
return Promise.resolve(result);
return { data: result.data };
} catch (axiosError) {
return Promise.reject(axiosError?.response?.data);
return {
error: {
status: axiosError?.response?.status,
data: axiosError?.response?.data,
message: axiosError?.message,
},
};
}
};

Expand Down
11 changes: 10 additions & 1 deletion src/api/emailApi.jsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createApi } from "@reduxjs/toolkit/query/react";
import {
ADMIN_INVITE_ENDPOINT,
EMPLOYEE_INVITE_ENDPOINT,
HTTP_METHODS,
USER_EMAIL_REDUCER_PATH,
Expand All @@ -18,7 +19,15 @@ export const userEmailApi = createApi({
invalidatesTags: ["user_email"],
transformResponse: (response) => response.data,
}),
adminInvite: builder.mutation({
query: ({ name, email }) => ({
url: ADMIN_INVITE_ENDPOINT,
method: HTTP_METHODS.POST,
data: { name, email },
}),
transformResponse: (response) => response.data,
}),
}),
});

export const { useUserEmailMutation } = userEmailApi;
export const { useUserEmailMutation, useAdminInviteMutation } = userEmailApi;
10 changes: 10 additions & 0 deletions src/api/profileApi.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
CREATE_PROFILE_ENDPOINT,
DELETE_PROFILE_ENDPOINT,
HTTP_METHODS,
INTRANET_EMPLOYEE_ENDPOINT,
PROFILE_COMPLETE_ENDPOINT,
PROFILE_GET_ENDPOINT,
PROFILE_LIST_ENDPOINT,
Expand Down Expand Up @@ -86,6 +87,14 @@ export const profileApi = createApi({
invalidatesTags: ["profile"],
transformResponse: (response) => response.data,
}),
getIntranetEmployee: builder.query({
query: (employeeId) => ({
url: INTRANET_EMPLOYEE_ENDPOINT.replace(":employee_id", employeeId),
method: HTTP_METHODS.GET,
_suppressToastForStatuses: [409],
}),
transformResponse: (response) => response.data,
}),
}),
});

Expand All @@ -98,4 +107,5 @@ export const {
useUpdateSequenceMutation,
useUpdateProfileStatusMutation,
useCompleteProfileMutation,
useLazyGetIntranetEmployeeQuery,
} = profileApi;
69 changes: 65 additions & 4 deletions src/components/Builder/BasicInfo/index.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import React, { useEffect, useState } from "react";
import toast from "react-hot-toast";
import { useNavigate } from "react-router-dom";
import { Button, Col, DatePicker, Form, Input, Row, Select, Space } from "antd";
import { useSelector } from "react-redux";
import { useLocation, useNavigate } from "react-router-dom";
import { Alert, Button, Col, DatePicker, Form, Input, Row, Select, Space } from "antd";
import { InfoCircleOutlined } from "@ant-design/icons";
import dayjs from "dayjs";
import PropTypes from "prop-types";
Expand All @@ -10,6 +11,7 @@ import {
useUpdateProfileMutation,
} from "../../../api/profileApi";
import {
ADMIN,
EDITOR_PROFILE_ROUTE,
GENDER,
PROFILE_DETAILS,
Expand All @@ -19,13 +21,17 @@ import {
import { parseDate } from "../../../helpers";

const BasicInfo = ({ profileData }) => {
const role = useSelector((state) => state.auth.role);
const [createProfileService, { isLoading: isCreating }] =
useCreateProfileMutation();
const [updateProfileService, { isLoading: isUpdating }] =
useUpdateProfileMutation();
const [formChange, setFormChange] = useState(false);
const [showIntranetBanner, setShowIntranetBanner] = useState(false);
const navigate = useNavigate();
const location = useLocation();
const [form] = Form.useForm();
const intranetData = location.state?.intranetData;

useEffect(() => {
if (profileData) {
Expand All @@ -37,6 +43,30 @@ const BasicInfo = ({ profileData }) => {
}
}, [profileData, form]);

// Pre-fill from Intranet data when coming from the sync flow
useEffect(() => {
if (intranetData && !profileData) {
form.setFieldsValue({
name: intranetData.name,
email: intranetData.email,
employee_id: intranetData.employeeId,
mobile: intranetData.mobileNumber,
gender: intranetData.gender,
years_of_experience: intranetData.yearsOfExperience,
designation: intranetData.designation,
linkedin_link: intranetData.linkedinUrl,
github_link: intranetData.githubUrl,
primary_skills: intranetData.primarySkills ?? [],
secondary_skills: intranetData.secondarySkills ?? [],
josh_joining_date: intranetData.joshJoiningDate
? dayjs(intranetData.joshJoiningDate)
: undefined,
});
setShowIntranetBanner(true);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [intranetData]);

const onFinish = async (values) => {
try {
if (values.years_of_experience || values.josh_joining_date) {
Expand All @@ -49,6 +79,11 @@ const BasicInfo = ({ profileData }) => {
values.josh_joining_date.format("MMM-YYYY");
}
}

if (values.employee_id && typeof values.employee_id === "string") {
values.employee_id = values.employee_id.trim();
}

let response;
if (profileData) {
if (formChange) {
Expand Down Expand Up @@ -87,8 +122,19 @@ const BasicInfo = ({ profileData }) => {
onValuesChange={() => setFormChange(true)}
initialValues={profileData || { description: PROFILE_DETAILS }}
>
{/* Intranet pre-fill info banner */}
{showIntranetBanner && (
<Alert
message="Form pre-filled from Intranet data. Please review and complete the remaining fields."
type="info"
showIcon
closable
onClose={() => setShowIntranetBanner(false)}
style={{ marginBottom: "20px" }}
/>
)}
<Row gutter={16}>
<Col span={12}>
<Col span={8}>
<Form.Item
name="name"
label="Full Name"
Expand All @@ -97,7 +143,7 @@ const BasicInfo = ({ profileData }) => {
<Input placeholder="First Middle Last" />
</Form.Item>
</Col>
<Col span={12}>
<Col span={8}>
<Form.Item
name="email"
label="Email"
Expand All @@ -112,6 +158,17 @@ const BasicInfo = ({ profileData }) => {
<Input placeholder="example@joshsoftware.com" />
</Form.Item>
</Col>
<Col span={8}>
<Form.Item
name="employee_id"
label="Employee ID"
>
<Input
placeholder="e.g. 101 or JIN1001"
disabled={role?.toLowerCase() !== ADMIN}
/>
</Form.Item>
</Col>
</Row>
<Row gutter={16}>
<Col span={12}>
Expand Down Expand Up @@ -302,6 +359,10 @@ BasicInfo.propTypes = {
primary_skills: PropTypes.array,
secondary_skills: PropTypes.array,
career_objectives: PropTypes.string,
employee_id: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
}),
josh_joining_date: PropTypes.oneOfType([
PropTypes.string,
Expand Down
Loading