DEV Community

Cover image for Hire+Plus! For Employees Here's how I built it (UI - Modals)
AjeaS
AjeaS

Posted on

Hire+Plus! For Employees Here's how I built it (UI - Modals)

Project Modal Component

inside components > modal > project-modal.component.tsx
ProjectPopupModalProps, defines the types of props being passed into this component. defaultFormFields fields of the modal to edit. Used defaultFormFields as the default state for projectFields.

import React, { ChangeEvent, useState } from 'react';
import { setProjects } from '../../app/features/profile/profileSlice';
import { useAppDispatch, useAppSelector } from '../../app/hooks';

interface ProjectPopupModalProps {
    isProjOpen: boolean;
    closeProjModal: () => void;
}
const defaultFormFields = {
    date: '',
    title: '',
    summary: '',
    github: '',
    projectUrl: '',
};
Enter fullscreen mode Exit fullscreen mode

Functionality

onHandleChange, onTextareaChange - handle state changes for the form fields.

resetFormFields - resets form fields after submission.

addProject - set projects for the profile.projects state within profileSlice, resets form, and close modal afterward.

const ProjectPopupModal: React.FC<ProjectPopupModalProps> = ({
    isProjOpen,
    closeProjModal,
}) => {
    const dispatch = useAppDispatch();

    const { profile } = useAppSelector((state) => state.profile);

    const [projectFields, setProjectFields] = useState(defaultFormFields);

    const onHandleChange = (e: ChangeEvent<HTMLInputElement>) => {
        const { name, value } = e.target;
        setProjectFields({ ...projectFields, [name]: value });
    };
    const onTextareaChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
        const { value } = e.target;
        setProjectFields({ ...projectFields, summary: value });
    };
    const resetFormFields = () => {
        setProjectFields(defaultFormFields);
    };
    const addProject = (e: ChangeEvent<HTMLFormElement>) => {
        e.preventDefault();
        dispatch(
            setProjects([
                {
                    date: projectFields.date,
                    title: projectFields.title,
                    summary: projectFields.summary,
                    github: projectFields.github,
                    projectUrl: projectFields.projectUrl,
                },
                ...profile.projects,
            ])
        );
        resetFormFields();
        setProjectFields(projectFields);
        closeProjModal();
    };
    return ( {/* removed for simplicity */} );
};

export default ProjectPopupModal;

Enter fullscreen mode Exit fullscreen mode

UI

Renders the pop-up modal if the isProjOpen is set to true, and all the fields to edit.

const ProjectPopupModal: React.FC<ProjectPopupModalProps> = ({
    isProjOpen,
    closeProjModal,
}) => {
    {/* removed for simplicity */}
    return (
        <div
            className="py-12 bg-gray-700 transition duration-150 ease-in-out z-10 absolute right-0 bottom-0 left-0 h-screen"
            id="modal"
            style={{ display: `${isProjOpen ? 'block' : 'none'}`, top: '850px' }}
        >
            <div role="alert" className="container mx-auto w-11/12 md:w-2/3 max-w-lg">
                <div className="relative py-8 px-5 md:px-10 bg-white shadow-md rounded border border-gray-400">
                    <div className="w-full flex justify-center text-gray-600 mb-3">
                        <svg
                            xmlns="http://www.w3.org/2000/svg"
                            className="icon icon-tabler icon-tabler-wallet"
                            width="52"
                            height="52"
                            viewBox="0 0 24 24"
                            strokeWidth="1"
                            stroke="currentColor"
                            fill="none"
                            strokeLinecap="round"
                            strokeLinejoin="round"
                        >
                            <path stroke="none" d="M0 0h24v24H0z" />
                            <path d="M17 8v-3a1 1 0 0 0 -1 -1h-10a2 2 0 0 0 0 4h12a1 1 0 0 1 1 1v3m0 4v3a1 1 0 0 1 -1 1h-12a2 2 0 0 1 -2 -2v-12" />
                            <path d="M20 12v4h-4a2 2 0 0 1 0 -4h4" />
                        </svg>
                    </div>
                    <h1 className="text-gray-800 font-lg font-bold tracking-normal leading-tight mb-4 text-center text-lg">
                        Add Project
                    </h1>
                    <form onSubmit={addProject}>
                        <label
                            htmlFor="name"
                            className="text-gray-800 text-sm font-bold leading-tight tracking-normal"
                        >
                            Project Name
                        </label>
                        <input
                            type="text"
                            required
                            name="title"
                            onChange={onHandleChange}
                            value={projectFields.title}
                            id="name"
                            className="mb-5 mt-2 text-gray-600 focus:outline-none focus:border focus:border-indigo-700 font-normal w-full h-10 flex items-center pl-3 text-sm border-gray-300 rounded border"
                            placeholder="Full stack react"
                        />
                        {/* Project Date */}
                        <label
                            htmlFor="date"
                            className="text-gray-800 text-sm font-bold leading-tight tracking-normal"
                        >
                            Date
                        </label>
                        <div className="relative mb-5 mt-2">
                            <div className="absolute right-0 text-gray-600 flex items-center pr-3 h-full cursor-pointer">
                                <svg
                                    xmlns="http://www.w3.org/2000/svg"
                                    className="icon icon-tabler icon-tabler-calendar-event"
                                    width="20"
                                    height="20"
                                    viewBox="0 0 24 24"
                                    strokeWidth="1.5"
                                    stroke="currentColor"
                                    fill="none"
                                    strokeLinecap="round"
                                    strokeLinejoin="round"
                                >
                                    <path stroke="none" d="M0 0h24v24H0z" />
                                    <rect x="4" y="5" width="16" height="16" rx="2" />
                                    <line x1="16" y1="3" x2="16" y2="7" />
                                    <line x1="8" y1="3" x2="8" y2="7" />
                                    <line x1="4" y1="11" x2="20" y2="11" />
                                    <rect x="8" y="15" width="2" height="2" />
                                </svg>
                            </div>
                            <input
                                name="date"
                                onChange={onHandleChange}
                                value={projectFields.date}
                                id="date"
                                className="text-gray-600 focus:outline-none focus:border focus:border-indigo-700 font-normal w-full h-10 flex items-center pl-3 text-sm border-gray-300 rounded border"
                                placeholder="MM/YY"
                            />
                        </div>
                        {/* project github */}
                        <label
                            htmlFor="github"
                            className="text-gray-800 text-sm font-bold leading-tight tracking-normal"
                        >
                            Project Github
                        </label>
                        <input
                            type="text"
                            name="github"
                            onChange={onHandleChange}
                            value={projectFields.github}
                            id="github"
                            className="mb-5 mt-2 text-gray-600 focus:outline-none focus:border focus:border-indigo-700 font-normal w-full h-10 flex items-center pl-3 text-sm border-gray-300 rounded border"
                            placeholder="www.projectOne@github.com"
                            required
                        />
                        <label
                            htmlFor="projectUrl"
                            className="text-gray-800 text-sm font-bold leading-tight tracking-normal"
                        >
                            Project URL
                        </label>
                        <input
                            name="projectUrl"
                            onChange={onHandleChange}
                            value={projectFields.projectUrl}
                            id="projectUrl"
                            className="mb-5 mt-2 text-gray-600 focus:outline-none focus:border focus:border-indigo-700 font-normal w-full h-10 flex items-center pl-3 text-sm border-gray-300 rounded border"
                            placeholder="www.coolwebapp.com"
                            required
                        />
                        <label
                            htmlFor="description"
                            className="text-gray-800 text-sm font-bold leading-tight tracking-normal"
                        >
                            Project Summary
                        </label>
                        <textarea
                            name="summary"
                            onChange={onTextareaChange}
                            value={projectFields.summary}
                            maxLength={300}
                            id="description"
                            className="mb-5 mt-2 text-gray-600 focus:outline-none focus:border focus:border-indigo-700 font-normal w-full flex items-center px-3 py-3 text-sm border-gray-300 rounded border"
                            placeholder="Authentication, testing, etc."
                            required
                        />
                        <div className="flex items-center justify-start w-full">
                            <button
                                type="submit"
                                className="focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-700 transition duration-150 ease-in-out hover:bg-indigo-600 bg-indigo-700 rounded text-white px-8 py-2 text-sm"
                            >
                                Submit
                            </button>
                            <button
                                type="button"
                                onClick={closeProjModal}
                                aria-label="close modal"
                                className="focus:outline-none focus:ring-2 focus:ring-offset-2  focus:ring-gray-400 ml-3 bg-gray-100 transition duration-150 text-gray-600 ease-in-out hover:border-gray-400 hover:bg-gray-300 border rounded px-8 py-2 text-sm"
                            >
                                Cancel
                            </button>
                        </div>
                    </form>
                    <button
                        className="cursor-pointer absolute top-0 right-0 mt-4 mr-5 text-gray-400 hover:text-gray-600 transition duration-150 ease-in-out rounded focus:ring-2 focus:outline-none focus:ring-gray-600"
                        aria-label="close modal"
                        onClick={closeProjModal}
                    >
                        <svg
                            xmlns="http://www.w3.org/2000/svg"
                            className="icon icon-tabler icon-tabler-x"
                            width="20"
                            height="20"
                            viewBox="0 0 24 24"
                            strokeWidth="2.5"
                            stroke="currentColor"
                            fill="none"
                            strokeLinecap="round"
                            strokeLinejoin="round"
                        >
                            <path stroke="none" d="M0 0h24v24H0z" />
                            <line x1="18" y1="6" x2="6" y2="18" />
                            <line x1="6" y1="6" x2="18" y2="18" />
                        </svg>
                    </button>
                </div>
            </div>
        </div>
    );
};

export default ProjectPopupModal;

Enter fullscreen mode Exit fullscreen mode

Screenshot

project modal


Experience Modal Component

inside components > modal > experience-modal.component.tsx
ExperiencePopupModalProps, defines the types of props being passed into this component. defaultFormFields fields of the modal to edit. Used defaultFormFields as the default state for experienceFields.

import { ChangeEvent, useState } from 'react';
import { setExperiences } from '../../app/features/profile/profileSlice';
import { useAppDispatch, useAppSelector } from '../../app/hooks';

interface ExperiencePopupModalProps {
    isOpen: boolean;
    closeModal: () => void;
}
const defaultFormFields = {
    date: '',
    position: '',
    positionSummary: '',
};
Enter fullscreen mode Exit fullscreen mode

Functionality

onHandleChange, onTextareaChange - handle state changes for the form fields.

resetFormFields - resets form fields after submission.

addExperience - set experiences for the profile.experience state within profileSlice, resets form, and close modal afterward.

const ExperiencePopupModal: React.FC<ExperiencePopupModalProps> = ({
    isOpen,
    closeModal,
}) => {
    const dispatch = useAppDispatch();
    const { profile } = useAppSelector((state) => state.profile);
    const [experienceFields, setExperienceFields] = useState(defaultFormFields);

    const onHandleChange = (e: ChangeEvent<HTMLInputElement>) => {
        const { name, value } = e.target;
        setExperienceFields({ ...experienceFields, [name]: value });
    };
    const onTextareaChange = (e: ChangeEvent<HTMLTextAreaElement>) => {
        const { value } = e.target;
        setExperienceFields({ ...experienceFields, positionSummary: value });
    };
    const resetFormFields = () => {
        setExperienceFields(defaultFormFields);
    };

    const addExperience = (e: ChangeEvent<HTMLFormElement>) => {
        e.preventDefault();
        dispatch(
            setExperiences([
                {
                    position: experienceFields.position,
                    positionSummary: experienceFields.positionSummary,
                    date: experienceFields.date,
                },
                ...profile.experience,
            ])
        );
        resetFormFields();
        closeModal();
    };
    return ( {/* removed for simplicity */} );
};

export default ExperiencePopupModal;

Enter fullscreen mode Exit fullscreen mode

UI

Renders the pop-up modal and all the fields to edit.

const ExperiencePopupModal: React.FC<ExperiencePopupModalProps> = ({
    isOpen,
    closeModal,
}) => {
    {/* removed for simplicity */}
    return (
        <div
            className="py-12 bg-gray-700 transition duration-150 ease-in-out z-10 absolute right-0 bottom-0 left-0 h-screen"
            id="modal"
            style={{ display: `${isOpen ? 'block' : 'none'}`, top: '880px' }}
        >
            <div role="alert" className="container mx-auto w-11/12 md:w-2/3 max-w-lg">
                <div className="relative py-8 px-5 md:px-10 bg-white shadow-md rounded border border-gray-400">
                    <div className="w-full flex justify-center text-gray-600 mb-3">
                        <svg
                            xmlns="http://www.w3.org/2000/svg"
                            className="icon icon-tabler icon-tabler-wallet"
                            width="52"
                            height="52"
                            viewBox="0 0 24 24"
                            strokeWidth="1"
                            stroke="currentColor"
                            fill="none"
                            strokeLinecap="round"
                            strokeLinejoin="round"
                        >
                            <path stroke="none" d="M0 0h24v24H0z" />
                            <path d="M17 8v-3a1 1 0 0 0 -1 -1h-10a2 2 0 0 0 0 4h12a1 1 0 0 1 1 1v3m0 4v3a1 1 0 0 1 -1 1h-12a2 2 0 0 1 -2 -2v-12" />
                            <path d="M20 12v4h-4a2 2 0 0 1 0 -4h4" />
                        </svg>
                    </div>
                    <h1 className="text-gray-800 font-lg font-bold tracking-normal leading-tight mb-4 text-center text-lg">
                        Add Job Experience
                    </h1>
                    <form onSubmit={addExperience}>
                        <label
                            htmlFor="title"
                            className="text-gray-800 text-sm font-bold leading-tight tracking-normal"
                        >
                            Position Title
                        </label>
                        <input
                            required
                            name="position"
                            onChange={onHandleChange}
                            value={experienceFields.position}
                            id="title"
                            className="mb-5 mt-2 text-gray-600 focus:outline-none focus:border focus:border-indigo-700 font-normal w-full h-10 flex items-center pl-3 text-sm border-gray-300 rounded border"
                            placeholder="Front-End Developer"
                        />
                        <label
                            htmlFor="description"
                            className="text-gray-800 text-sm font-bold leading-tight tracking-normal"
                        >
                            Position Summary
                        </label>
                        <textarea
                            required
                            name="description"
                            onChange={onTextareaChange}
                            value={experienceFields.positionSummary}
                            maxLength={1000}
                            id="description"
                            className="mb-5 mt-2 text-gray-600 focus:outline-none focus:border focus:border-indigo-700 font-normal w-full flex items-center px-3 py-3 text-sm border-gray-300 rounded border"
                            placeholder="Job details..."
                        />
                        <label
                            htmlFor="date"
                            className="text-gray-800 text-sm font-bold leading-tight tracking-normal"
                        >
                            Date
                        </label>
                        <div className="relative mb-5 mt-2">
                            <div className="absolute right-0 text-gray-600 flex items-center pr-3 h-full cursor-pointer">
                                <svg
                                    xmlns="http://www.w3.org/2000/svg"
                                    className="icon icon-tabler icon-tabler-calendar-event"
                                    width="20"
                                    height="20"
                                    viewBox="0 0 24 24"
                                    strokeWidth="1.5"
                                    stroke="currentColor"
                                    fill="none"
                                    strokeLinecap="round"
                                    strokeLinejoin="round"
                                >
                                    <path stroke="none" d="M0 0h24v24H0z" />
                                    <rect x="4" y="5" width="16" height="16" rx="2" />
                                    <line x1="16" y1="3" x2="16" y2="7" />
                                    <line x1="8" y1="3" x2="8" y2="7" />
                                    <line x1="4" y1="11" x2="20" y2="11" />
                                    <rect x="8" y="15" width="2" height="2" />
                                </svg>
                            </div>
                            <input
                                required
                                name="date"
                                onChange={onHandleChange}
                                value={experienceFields.date}
                                id="date"
                                className="text-gray-600 focus:outline-none focus:border focus:border-indigo-700 font-normal w-full h-10 flex items-center pl-3 text-sm border-gray-300 rounded border"
                                placeholder="MM/YY"
                            />
                        </div>

                        <div className="flex items-center justify-start w-full">
                            <button
                                type="submit"
                                className="focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-700 transition duration-150 ease-in-out hover:bg-indigo-600 bg-indigo-700 rounded text-white px-8 py-2 text-sm"
                            >
                                Submit
                            </button>
                            <button
                                aria-label="close modal"
                                type="button"
                                onClick={closeModal}
                                className="focus:outline-none focus:ring-2 focus:ring-offset-2  focus:ring-gray-400 ml-3 bg-gray-100 transition duration-150 text-gray-600 ease-in-out hover:border-gray-400 hover:bg-gray-300 border rounded px-8 py-2 text-sm"
                            >
                                Cancel
                            </button>
                        </div>
                    </form>
                    <button
                        className="cursor-pointer absolute top-0 right-0 mt-4 mr-5 text-gray-400 hover:text-gray-600 transition duration-150 ease-in-out rounded focus:ring-2 focus:outline-none focus:ring-gray-600"
                        aria-label="close modal"
                        onClick={closeModal}
                    >
                        <svg
                            xmlns="http://www.w3.org/2000/svg"
                            className="icon icon-tabler icon-tabler-x"
                            width="20"
                            height="20"
                            viewBox="0 0 24 24"
                            strokeWidth="2.5"
                            stroke="currentColor"
                            fill="none"
                            strokeLinecap="round"
                            strokeLinejoin="round"
                        >
                            <path stroke="none" d="M0 0h24v24H0z" />
                            <line x1="18" y1="6" x2="6" y2="18" />
                            <line x1="6" y1="6" x2="18" y2="18" />
                        </svg>
                    </button>
                </div>
            </div>
        </div>
    );
};

export default ExperiencePopupModal;

Enter fullscreen mode Exit fullscreen mode

Screenshot

experience modal

That's all for the UI/Modals portion of the project, stay tuned!

Latest comments (0)