하이어+플러스! 직원을 위해 제가 구축한 방법은 다음과 같습니다(UI - 프로필).
86822 단어 tutorialprogrammingreactwebdev
개요: 프로필과 관련된 모든 보기 및 기능, 호출된 모든 함수는 profileReducer에서 가져옵니다.
프로필 경로 페이지
인사이드
routes > profile > profile-page.tsx
호출할 함수를 지원하는 가져오기.마운트 시
id
에서 프로필을 가져옵니다. useParams
에서 가져옵니다. 편집이 true로 설정된 경우 편집 프로필 구성 요소를 렌더링합니다. 그렇지 않은 경우 실제 프로필 구성 요소를 렌더링합니다.import { useEffect } from 'react';
import { useParams } from 'react-router';
import { getProfileById } from '../../app/features/profile/profileSlice';
import BeatLoader from 'react-spinners/BeatLoader';
import { useAppSelector, useAppDispatch } from '../../app/hooks';
import Profile from '../../components/profile/profile.component';
import EditProfile from '../../components/profile/edit-profile.component';
const ProfilePage = () => {
const { id } = useParams();
const dispatch = useAppDispatch();
const { isLoading, isEditting } = useAppSelector((state) => state.profile);
useEffect(() => {
dispatch(getProfileById(id));
}, [id, dispatch]);
return (
<>
{isLoading ? (
<div className="text-center p-20">
<BeatLoader color="#ffffff" />
</div>
) : (
<>{isEditting ? <EditProfile /> : <Profile />}</>
)}
</>
);
};
export default ProfilePage;
프로필 구성 요소
인사이드
components > profile > profile.component.tsx
호출할 함수를 지원하는 가져오기.기능
settingEditView
토글isEditting
하여 편집 프로필 구성 요소를 표시할지 여부를 결정합니다. removeItem
는 (필터로) 프로젝트를 제거하고 새 결과를 project
상태로 설정합니다. UI에 정보를 표시하기 위해 currentUser
를 사용합니다.import { setEditView, setProjects } from '../../app/features/profile/profileSlice';
import { useAppDispatch, useAppSelector } from '../../app/hooks';
import Experience from '../experience/experience-component';
import Project from '../project/project-component';
const Profile = () => {
const dispatch = useAppDispatch();
const { profile, isEditting } = useAppSelector((state) => state.profile);
const { currentUser } = useAppSelector((state) => state.auth);
const settingEditView = () => {
dispatch(setEditView(!isEditting));
};
const removeItem = (id: number) => {
const newProjects = profile.projects.filter((_, i) => i !== id);
dispatch(setProjects(newProjects));
};
return ( {/* removed for simplicity */} )
}
UI
프로필 정보(프로젝트, 경험, 기술, 요약, 웹 사이트 URL 등)를 렌더링합니다. 현재 사용자
id
와 프로필 ID가 일치하지 않으면 프로필 편집 버튼을 렌더링하지 않습니다. Projects
및 Experiences
는 모두 별도의 구성 요소입니다. 기본적으로 프로필을 편집할 때까지 데이터가 표시되지 않습니다.const Profile = () => {
{/* removed for simplicity */}
return (
<>
{profile && (
<>
<section style={{ backgroundColor: '#252731' }}>
<div className="container mx-auto py-5 px-5 md:px-0 text-right text-white flex justify-between">
<div className="flex justify-center text-md text-slate-200">
{profile.isForHire ? (
<p>Actively looking for work</p>
) : (
<p>Not currently looking for work</p>
)}
</div>
{currentUser.uid !== profile.id ? null : (
<button
onClick={settingEditView}
className="underline text-md text-indigo-500"
>
Edit Profile
</button>
)}
</div>
<div className="md:px-12 lg:px-24 max-w-7xl relative items-center w-full px-5 py-5 mx-auto">
<div className="mx-auto flex flex-col w-full max-w-lg mb-12 text-center">
<p className="mb-5 font-medium text-2xl text-white">
{currentUser.displayName}
</p>
<img
alt="testimonial"
className="inline-block object-cover object-center w-20 h-20 mx-auto mb-8 rounded-full"
src="https://picsum.photos/200"
/>
<div className="flex justify-center">
{profile.headline ? (
<p className="text-base leading-relaxed font-color pr-2">
{profile.headline}
</p>
) : null}
{profile.websiteURL ? (
<>
<a
href={profile.websiteURL}
className="text-base leading-relaxed text-indigo-500 border-l-2 border-gray-500 pl-2"
>
Live Website
</a>
</>
) : (
<p className="font-color">No website to show</p>
)}
</div>
</div>
</div>
</section>
<div className="divide-y divide-gray-700" key={profile.id}>
<section className="text-gray-600 body-font mt-2">
<div className="container px-10 py-20 mx-auto">
<div className="flex flex-col w-full mx-auto">
<div className="w-full mx-auto">
<h2 className="sm:text-3xl text-2xl my-5 font-bold">
About Me
</h2>
<p className="lg:w-3/4 about-me font-color">
{profile.summary ? profile.summary : 'No info to show'}
</p>
</div>
</div>
</div>
</section>
<section className="text-gray-600 body-font overflow-hidden">
<div className="container px-10 py-20 mx-auto">
<div className="flex flex-col w-full mx-auto">
<div className="w-full mx-auto">
<h2 className="sm:text-3xl text-2xl mb-5 font-bold">
Skills
</h2>
{profile.skills.length ? (
<ul className="flex flex-wrap">
{profile.skills.map((skill, id) => {
return (
<li
className="mr-2 my-2 text-white px-4 py-2 rounded-3xl bg-indigo-700 cursor-pointer["
key={id}
>
{skill}
</li>
);
})}
</ul>
) : (
<p className="font-color">No skills to show</p>
)}
</div>
</div>
</div>
</section>
{/* Experience starts */}
<section className="text-gray-600 body-font overflow-hidden">
<div className="container px-10 py-20 mx-auto">
<div className="-my-8 mx-auto">
<h2 className="text-3xl my-8 mb-5 font-bold">Experience</h2>
{profile.experience.length ? (
<ol className="border-l-2 border-indigo-700 mt-10">
{profile.experience.map((exp, index) => {
return (
<Experience
experienceData={exp}
key={index}
itemIndex={index}
/>
);
})}
</ol>
) : (
<p className="font-color">No experiences to show</p>
)}
</div>
</div>
</section>
{/* Projects starts */}
<section className="text-gray-600 body-font">
<div className="container px-10 py-24 mx-auto">
<h2 className="sm:text-3xl text-2xl font-bold title-font mb-5">
Projects
</h2>
{profile.projects.length ? (
<div className="container py-5 mx-auto">
<div className="flex flex-wrap -m-4">
{profile.projects.map((proj, index) => {
return (
<Project
project={proj}
key={index}
itemIndex={index}
removeItem={removeItem}
/>
);
})}
</div>
</div>
) : (
<p className="font-color">No projects to show</p>
)}
</div>
</section>
</div>
</>
)}
</>
);
};
export default Profile;
스크린샷
프로필 구성 요소 편집
인사이드
components > profile > edit-profile.component.tsx
가져오기: TagsInput
태그를 추가하기 위한 반응 패키지, 기술을 추가하는 데 사용합니다. ExperiencePopupModal
프로필에 작업 경험을 추가하기 위한 팝업 모달, ProjectPopupModal
프로젝트를 추가하기 위한 팝업 모달입니다. 나머지는 적절할 때 호출하는 profileReducer
의 기능입니다.import { ChangeEvent, useState } from 'react';
import { useNavigate } from 'react-router';
import { TagsInput } from 'react-tag-input-component';
import {
setEditView,
setProjects,
updateProfileById,
} from '../../app/features/profile/profileSlice';
import { useAppDispatch, useAppSelector } from '../../app/hooks';
import Experience from '../experience/experience-component';
import ExperiencePopupModal from '../modal/experience-modal.component';
import ProjectPopupModal from '../modal/project-modal.component';
import Project from '../project/project-component';
기능
토글링을 위해 업데이트해야 하는 모든 필드
formFields
, skills
및 checked
를 고용 상태로 처리합니다. isOpen
열기/닫기 경험 모달용. isProjOpen
프로젝트 모달 열기/닫기용.handleCheckedChange
- isForHire 상태 전환, 결정사용자가 일자리를 찾고 있는지 여부.
settingEditView
- 편집 보기 전환onHandleChange
- formFields
상태에 대한 변경 사항 처리onTextAreaChange
- 텍스트 영역에 대한 변경 사항 처리updateProfile
- 프로필을 업데이트하고, 편집 보기를 false로 설정하고, 기본 페이지로 리디렉션합니다.removeItem
- id
로 프로젝트를 제거합니다(필터 사용).closeModal
- 경험치 모달을 닫습니다.closeProjModal
- 프로젝트 모달을 닫습니다.const EditProfile = () => {
const { profile, isEditting } = useAppSelector((state) => state.profile);
const { currentUser } = useAppSelector((state) => state.auth);
const dispatch = useAppDispatch();
const navigate = useNavigate();
const [formFields, setFormFields] = useState({
headline: profile.headline ? profile.headline : '',
summary: profile.summary ? profile.summary : '',
websiteURL: profile.websiteURL ? profile.websiteURL : '',
});
const [skills, setSkills] = useState<string[]>(
profile.skills ? profile.skills : []
);
const [checked, setChecked] = useState<boolean>(profile.isForHire);
const [isOpen, setIsOpen] = useState(false);
const [isProjOpen, setIsProjOpen] = useState(false);
const handleCheckedChange = () => {
setChecked(!checked);
};
const settingEditView = () => {
dispatch(setEditView(!isEditting));
};
const onHandleChange = (event: ChangeEvent<HTMLInputElement>) => {
const { name, value } = event.target;
setFormFields({ ...formFields, [name]: value });
};
const onTextAreaChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
setFormFields({ ...formFields, summary: event.target.value });
};
const updateProfile = async () => {
dispatch(
updateProfileById({
id: profile.id,
headline: formFields.headline,
summary: formFields.summary,
isForHire: checked,
websiteURL: formFields.websiteURL,
skills: skills,
experience: profile.experience,
projects: profile.projects,
})
);
dispatch(setEditView(false));
navigate('/app');
};
const removeItem = (id: number) => {
const newProjects = profile.projects.filter((_, i) => i !== id);
dispatch(setProjects(newProjects));
};
const closeModal = () => {
setIsOpen(false);
};
const closeProjModal = () => {
setIsProjOpen(false);
};
return ( {/* removed for simplicity */} );
};
export default EditProfile;
UI
편집할 수 있는 모든 필드를 렌더링합니다. 경험 모달 또는 프로젝트 모달을 여는 버튼과 함께.
const EditProfile = () => {
{/* removed for simplicity */}
return (
<>
<section style={{ backgroundColor: '#252731' }}>
<div className="container mx-auto py-5 text-right text-white flex justify-between">
<div>
<label
htmlFor="toggle-example"
className="flex items-center cursor-pointer relative mb-4"
>
<input
onChange={handleCheckedChange}
checked={checked}
type="checkbox"
id="toggle-example"
className="sr-only"
/>
<div className="toggle-bg bg-gray-200 border-2 border-gray-200 h-6 w-11 rounded-full"></div>
<span className="ml-3 text-slate-200 text-md font-medium">
Are you looking for work?
</span>
</label>
</div>
<div>
<button
onClick={updateProfile}
className="mr-2 text-lg text-indigo-500"
>
Update
</button>
<button onClick={settingEditView}>Go Back</button>
</div>
</div>
<div className="md:px-12 lg:px-24 max-w-7xl relative items-center w-full px-5 py-5 mx-auto">
<div className="mx-auto flex flex-col w-full max-w-lg mb-12 text-center">
<p className="mb-5 font-medium text-2xl text-white">
{currentUser.displayName}
</p>
<img
alt="testimonial"
className="inline-block object-cover object-center w-20 h-20 mx-auto mb-8 rounded-full"
src="https://picsum.photos/200"
/>
<div className="flex justify-center">
<input
className="font-color mr-3 primary-bg-color input-border-color block w-full px-5 py-3 mt-2 text-base text-neutral-600 placeholder-gray-500 transition duration-500 ease-in-out transform border border-transparent rounded-lg focus:outline-none focus:border-transparent focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-300 apearance-none"
id="headline"
value={formFields.headline}
onChange={onHandleChange}
name="headline"
placeholder="e.g. Front-end Developer"
/>
<input
className="font-color primary-bg-color input-border-color block w-full px-5 py-3 mt-2 text-base text-neutral-600 placeholder-gray-500 transition duration-500 ease-in-out transform border border-transparent rounded-lg focus:outline-none focus:border-transparent focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-300 apearance-none"
id="websiteURL"
value={formFields.websiteURL}
onChange={onHandleChange}
name="websiteURL"
placeholder="Add website url..."
/>
</div>
</div>
</div>
</section>
<section>
<div className="divide-y divide-gray-700">
<section className="text-gray-600 body-font mt-2">
<div className="container px-5 py-20 mx-auto">
<div className="flex flex-col w-full mx-auto">
<div className="w-full mx-auto">
<h2 className="sm:text-3xl text-2xl my-5 font-bold">
About Me
</h2>
<div>
<textarea
maxLength={4000}
rows={5}
className="font-color input-border-color secondary-bg-color block w-full px-5 py-3 mt-2 text-base text-neutral-600 placeholder-gray-500 transition duration-500 ease-in-out transform border border-transparent rounded-lg focus:outline-none focus:border-transparent focus:ring-2 focus:ring-white focus:ring-offset-2 focus:ring-offset-gray-300 apearance-none autoexpand"
id="summary"
name="summary"
value={formFields.summary}
onChange={onTextAreaChange}
placeholder="Message..."
></textarea>
</div>
</div>
</div>
</div>
</section>
<section className="text-gray-600 body-font overflow-hidden">
<div className="container px-5 py-20 mx-auto">
<div className="flex flex-col w-full mx-auto">
<div className="w-full mx-auto">
<h2 className="sm:text-3xl text-2xl mb-5 font-bold">
Skills
</h2>
<TagsInput
value={skills}
onChange={setSkills}
name="skills"
placeHolder="Add skills here..."
/>
</div>
</div>
</div>
</section>
{/* Experience starts */}
<section className="text-gray-600 body-font overflow-hidden">
<div className="container px-5 py-20 mx-auto">
<div className="-my-8 mx-auto">
<h2 className="sm:text-3xl text-2xl my-5 font-bold">
Experience
</h2>
<button
onClick={() => setIsOpen(true)}
className="block mb-5 text-white bg-indigo-700 focus:ring-4 focus:outline-none font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-indigo-600 dark:hover:bg-indigo-700 dark:focus:ring-indigo-800"
type="button"
data-modal-toggle="defaultModal"
>
Add Experience
</button>
<ExperiencePopupModal isOpen={isOpen} closeModal={closeModal} />
<p className="mb-5 font-color">
Be sure to <b>'Update'</b> for these changes to take effect :)
</p>
{profile.experience.length ? (
<ol className="border-l-2 border-indigo-700">
{profile.experience.map((exp, index) => {
return (
<Experience
experienceData={exp}
key={index}
itemIndex={index}
/>
);
})}
</ol>
) : null}
</div>
</div>
</section>
{/* Projects starts */}
<section className="text-gray-600 body-font">
<div className="container px-5 py-24 mx-auto">
<div className="text-left mb-5">
<h2 className="sm:text-3xl text-2xl font-bold title-font mb-5">
Projects
</h2>
<button
onClick={() => setIsProjOpen(true)}
className="block text-white bg-indigo-700 focus:ring-4 focus:outline-none font-medium rounded-lg text-sm px-5 py-2.5 text-center dark:bg-indigo-600 dark:hover:bg-indigo-700 dark:focus:ring-indigo-800"
type="button"
data-modal-toggle="defaultModal"
>
Add Project
</button>
<ProjectPopupModal
isProjOpen={isProjOpen}
closeProjModal={closeProjModal}
/>
</div>
<p className="mb-5 font-color">
Be sure to <b>'Update'</b> for these changes to take effect :)
</p>
<div className="flex flex-wrap -m-4">
{profile.projects.length
? profile.projects.map((project, index) => {
return (
<Project
project={project}
key={index}
itemIndex={index}
removeItem={removeItem}
/>
);
})
: null}
</div>
</div>
</section>
</div>
</section>
</>
);
};
export default EditProfile;
스크린샷
편집 상태
비편집 상태
프로젝트의 UI/프로필 부분은 여기까지입니다. 계속 지켜봐 주세요!
Reference
이 문제에 관하여(하이어+플러스! 직원을 위해 제가 구축한 방법은 다음과 같습니다(UI - 프로필).), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/ajeasmith/hireplus-for-employees-heres-how-i-built-it-ui-profile-3280텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)