Compare commits

...

5 Commits

Author SHA1 Message Date
victorAnumudu e6153e0b3d update profile validation with formik and yup 2023-04-25 19:57:40 +01:00
DESKTOP-GBA0BK8\Admin 02fe8cb399 npm i yup npm i formik 2023-04-25 08:40:18 -04:00
ameye 0819105fcb Merge branch 'profile_page_styling' of WrenchBoard/Users-Wrench into master 2023-04-25 12:28:13 +00:00
victorAnumudu 9070d99b1d profile page styling 2023-04-25 13:24:24 +01:00
ameye 2da53ecc2e Merge branch 'profile_preload_info' of WrenchBoard/Users-Wrench into master 2023-04-25 10:23:14 +00:00
3 changed files with 284 additions and 296 deletions
+3 -1
View File
@@ -13,6 +13,7 @@
"chartjs": "^0.3.24", "chartjs": "^0.3.24",
"cors": "^2.8.5", "cors": "^2.8.5",
"faker": "^6.6.6", "faker": "^6.6.6",
"formik": "^2.2.9",
"react": "^18.0.0", "react": "^18.0.0",
"react-chartjs-2": "^4.1.0", "react-chartjs-2": "^4.1.0",
"react-countup": "^6.2.0", "react-countup": "^6.2.0",
@@ -25,7 +26,8 @@
"react-toastify": "^9.0.1", "react-toastify": "^9.0.1",
"redux": "^4.2.0", "redux": "^4.2.0",
"slick-carousel": "^1.8.1", "slick-carousel": "^1.8.1",
"web-vitals": "^1.0.1" "web-vitals": "^1.0.1",
"yup": "^1.1.1"
}, },
"scripts": { "scripts": {
"start": "react-scripts start", "start": "react-scripts start",
@@ -12,7 +12,9 @@ export default function InputCom({
inputHandler, inputHandler,
value, value,
forgotPassword, forgotPassword,
onClick onClick,
disable,
blurHandler,
}) { }) {
return ( return (
<div className="input-com"> <div className="input-com">
@@ -36,7 +38,8 @@ export default function InputCom({
type={type} type={type}
id={name} id={name}
name={name} name={name}
required readOnly={disable}
onBlur={blurHandler}
/> />
{iconName && ( {iconName && (
<div className="absolute right-6 bottom-[10px] z-10"> <div className="absolute right-6 bottom-[10px] z-10">
+126 -143
View File
@@ -7,6 +7,41 @@ import LoadingSpinner from "../../Spinners/LoadingSpinner";
import {toast} from 'react-toastify' import {toast} from 'react-toastify'
import {Formik, Form} from 'formik'
import * as Yup from 'yup'
const validationSchema = Yup.object().shape({
email: Yup.string()
.email('Wrong email format')
.min(3, 'Minimum 3 characters')
.max(50, 'Maximum 50 characters')
.required('Email is required'),
firstname: Yup.string()
.min(3, 'Minimum 3 characters')
.max(25, 'Maximum 25 characters')
.required('Firstname is required'),
lastname: Yup.string()
.min(3, 'Minimum 3 characters')
.max(25, 'Maximum 25 characters')
.required('Lastname is required'),
city: Yup.string()
.min(3, 'Minimum 3 characters')
.max(25, 'Maximum 25 characters')
.required('City is required'),
state: Yup.string()
.min(3, 'Minimum 3 characters')
.max(25, 'Maximum 25 characters')
.required('State is required'),
})
const initialValues = {
firstname: '',
lastname: '',
state: '',
city: '',
email: ''
}
export default function PersonalInfoTab({ export default function PersonalInfoTab({
datas, datas,
frstNmeHndlr, frstNmeHndlr,
@@ -47,40 +82,18 @@ export default function PersonalInfoTab({
email: '' email: ''
}) })
const handleChange = ({target:{name, value}}) => { // const handleChange = ({target:{name, value}}) => {
setInputs(prev => ({...prev, [name]:value})) // setInputs(prev => ({...prev, [name]:value}))
} // }
const handleUpdateUser = ()=> { const handleUpdateUser = (values, helpers)=> {
setRequestState({message: '', loading: true, status: false}) setRequestState({message: '', loading: true, status: false})
let {firstname, lastname, state, city, email} = inputs apiCall.updateProfile(values).then((res)=>{
if(!firstname || !lastname || !state || !city || !email){
setRequestState({message: 'Please Fill all fields', loading: false, status: false})
return
}
//checks if email is a valid email address
let regEx = /^[^0-9][a-zA-Z0-9._%+-]+@[a-zA-Z]+(\.[a-zA-Z]+)+$/;
if (regEx.test(email) == false) {
setRequestState({message: 'Your Email is Invalid', loading: false, status: false})
return
}
apiCall.updateProfile(inputs).then((res)=>{
if(res.data.internal_return < 0){ if(res.data.internal_return < 0){
setRequestState({message: 'Profile Was unable to update', loading: false, status: false}) setRequestState({message: 'Profile Was unable to update', loading: false, status: false})
return return
} }
setInputs({
firstname: '',
lastname: '',
state: '',
city: '',
email: ''
})
// setRequestState({message: 'Profile update successfully', loading: false, status: true}) // setRequestState({message: 'Profile update successfully', loading: false, status: true})
toast.success("Update Successful"); toast.success("Update Successful");
setTimeout(()=>{navigate('/',{replace:true})},1000) setTimeout(()=>{navigate('/',{replace:true})},1000)
@@ -89,7 +102,7 @@ export default function PersonalInfoTab({
}) })
} }
const loadProfile = ()=>{ const loadProfile = ()=>{ // function to load user profile
apiCall.loadProfile().then((res)=>{ apiCall.loadProfile().then((res)=>{
if(res.data.internal_return < 0){ if(res.data.internal_return < 0){
setProfile(prev => ({...prev, loading: false, status: true})) setProfile(prev => ({...prev, loading: false, status: true}))
@@ -113,13 +126,20 @@ export default function PersonalInfoTab({
},[]) },[])
return ( return (
<div className="personal-info-tab w-full flex flex-col justify-between">
{profile.loading ? profile.loading ?
<div className="personal-info-tab w-full flex flex-col justify-between">
<div className="p-3"> <div className="p-3">
<LoadingSpinner size='32' color='sky-blue' /> <LoadingSpinner size='32' color='sky-blue' />
</div> </div>
</div>
: :
<div className="personal-info-tab w-full flex flex-col justify-between">
<Formik initialValues={inputs} validationSchema={validationSchema} onSubmit={handleUpdateUser}>
{(props => {
return (
<Form>
{
profile.data.length ? profile.data.length ?
profile.data.map((item, index) => ( profile.data.map((item, index) => (
<div key={index} className="flex flex-col-reverse sm:flex-row"> <div key={index} className="flex flex-col-reverse sm:flex-row">
@@ -127,105 +147,117 @@ export default function PersonalInfoTab({
<div className="fields w-full"> <div className="fields w-full">
{/* inputs starts here */} {/* inputs starts here */}
{/* username */} {/* username */}
<div className='profile-input my-3'> <div className="field w-full mb-6">
<label className='w-full text-slate-600 text-lg'>Username <span className='text-red-500'>*</span></label> <InputCom
<input className='w-full p-3 text-lg text-slate-500 bg-slate-200 opacity-90 rounded-md outline-0 placeholder:text-slate-500 placeholder:text-lg' label="User Name"
value={item.username}
name='username'
type="text" type="text"
placeholder='username@gamil.com' name="username"
disabled placeholder=""
value={item.username}
disable={true}
/> />
</div> </div>
{/* Email */} {/* Email */}
<div className='profile-input my-3'> <div className="field w-full mb-6">
<label className='w-full text-slate-600 text-lg'>Email <span className='text-red-500'>*</span></label> <InputCom
<input className='w-full p-3 text-lg text-slate-500 bg-slate-200 opacity-90 rounded-md outline-0 placeholder:text-slate-500 placeholder:text-lg' label="Email"
value={inputs.email}
name='email'
type="text" type="text"
placeholder='Email' name="email"
onChange={handleChange} placeholder="Email"
value={props.values.email}
inputHandler={props.handleChange}
blurHandler={props.handleBlur}
/> />
{(props.errors.email && props.touched.email) && <p className="text-sm text-red-500">{props.errors.email}</p>}
</div> </div>
{/* first name and last name */}
{/* Fullname */} <div className="xl:flex xl:space-x-7 mb-6">
<div className='profile-input my-3'> <div className="field w-full mb-6 xl:mb-0">
<label className='w-full text-slate-600 text-lg'>Fullname <span className='text-red-500'>*</span></label> <InputCom
<div className="w-full flex items-center justify-center space-x-1 space-y-1"> label="First Name"
<input className='p-3 text-lg text-slate-500 bg-slate-100 rounded-md outline-0 placeholder:text-slate-500 placeholder:text-lg'
value={inputs.firstname}
name='firstname'
type="text" type="text"
placeholder='Firstname' name="firstname"
onChange={handleChange} placeholder="First Name"
value={props.values.firstname}
inputHandler={props.handleChange}
blurHandler={props.handleBlur}
/> />
<input className='p-3 text-lg text-slate-500 bg-slate-100 rounded-md outline-0 placeholder:text-slate-500 placeholder:text-lg' {(props.errors.firstname && props.touched.firstname) && <p className="text-sm text-red-500">{props.errors.firstname}</p>}
value={inputs.lastname} </div>
name='lastname' <div className="field w-full">
<InputCom
label="Last Name"
type="text" type="text"
placeholder='Lastname' name="lastname"
onChange={handleChange} placeholder="Last Name"
value={props.values.lastname}
inputHandler={props.handleChange}
blurHandler={props.handleBlur}
/> />
{(props.errors.lastname && props.touched.lastname) && <p className="text-sm text-red-500">{props.errors.lastname}</p>}
</div> </div>
</div> </div>
{/* Country */} {/* Country */}
<div className='profile-input my-3'> <div className="field w-full mb-6">
<label className='w-full text-slate-600 text-lg'>Country <span className='text-red-500'>*</span></label> <InputCom
<input className='w-full p-3 text-lg text-slate-500 bg-slate-200 opacity-90 rounded-md outline-0 placeholder:text-slate-500 placeholder:text-lg' label="Country"
value={item.country}
name='country'
type="text" type="text"
disabled name="country"
value={item.country}
disable={true}
/> />
</div> </div>
{/* State/Province */} {/* State/Province */}
<div className='profile-input my-3'> <div className="field w-full mb-6">
<label className='w-full text-slate-600 text-lg'>State/Province <span className='text-red-500'>*</span></label> <InputCom
<input className='w-full p-3 text-lg text-slate-500 bg-slate-100 rounded-md outline-0 placeholder:text-slate-500 placeholder:text-lg' label="State/Province"
value={inputs.state}
name='state'
type="text" type="text"
placeholder='State' name="state"
onChange={handleChange} placeholder="State"
value={props.values.state}
inputHandler={props.handleChange}
blurHandler={props.handleBlur}
/> />
{(props.errors.state && props.touched.state) && <p className="text-sm text-red-500">{props.errors.state}</p>}
</div> </div>
{/* City */} {/* City */}
<div className='profile-input my-3'> <div className="field w-full mb-6">
<label className='w-full text-slate-600 text-lg'>City <span className='text-red-500'>*</span></label> <InputCom
<input className='w-full p-3 text-lg text-slate-500 bg-slate-100 rounded-md outline-0 placeholder:text-slate-500 placeholder:text-lg' label="City"
value={inputs.city}
name='city'
type="text" type="text"
placeholder='City' name="city"
onChange={handleChange} placeholder="City"
value={props.values.city}
inputHandler={props.handleChange}
blurHandler={props.handleBlur}
/> />
{(props.errors.city && props.touched.city) && <p className="text-sm text-red-500">{props.errors.city}</p>}
</div> </div>
{/* Preferred Communication*/} {/* Preferred Communication*/}
<div className='profile-input my-3'> <div className='field w-full mb-6 md:flex items-center space-x-4'>
<label className='text-slate-600 text-lg'>Pref. Communication <span className='text-red-500'>*</span></label> <label className='input-label text-[#181c32] dark:text-white text-base font-semibold'>Pref. Communication</label>
<div className="check-box"> <div className="check-box">
<div className="flex items-center justify-start"> <div className="flex items-center justify-start">
<div className="check-input flex items-center"> <div className="check-input flex items-center mr-1">
<input className="mx-2 w-4 h-4 cursor-pointer" type="checkbox" name="prefcomm1" id="" /> <input className="w-4 h-4 cursor-pointer" type="checkbox" name="prefcomm1" id="" />
<span className="text-slate-600 text-lg">Email</span> <span className="mx-2 text-base text-dark-gray dark:text-white">Email</span>
</div> </div>
<div className="check-input flex items-center"> <div className="check-input flex items-center">
<input className="mx-2 w-4 h-4 cursor-pointer" type="checkbox" name="prefcomm2" id="" /> <input className="w-4 h-4 cursor-pointer" type="checkbox" name="prefcomm2" id="" />
<span className="text-slate-600 text-lg">Phone</span> <span className="mx-2 text-base text-dark-gray dark:text-white">Phone</span>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
{/* Allow Promotions */} {/* Allow Promotions */}
<div className='profile-input my-3 flex items-center space-x-4'> <div className='field w-full mb-6 flex items-center space-x-4'>
<label className='text-slate-600 text-lg'>Allow Promotions</label> <label className='input-label text-[#181c32] dark:text-white text-base font-semibold'>Allow Promotions</label>
<div className="cursor-pointer flex items-center" onClick={()=>setTogglePromotion(prev => !prev)}> <div className="cursor-pointer flex items-center" onClick={()=>setTogglePromotion(prev => !prev)}>
<div className={`h-6 w-8 mr-1 p-1 ${togglePromotion ? 'bg-sky-blue flex justify-end items-center': 'bg-slate-200'} rounded-full transition`}> <div className={`h-6 w-8 mr-1 p-1 ${togglePromotion ? 'bg-sky-blue flex justify-end items-center': 'bg-slate-200'} rounded-full transition`}>
<div className="w-4 h-full bg-white rounded-full"></div> <div className="w-4 h-full bg-white rounded-full"></div>
@@ -291,57 +323,6 @@ export default function PersonalInfoTab({
</div> </div>
</div> </div>
</div> </div>
<div className="update-profile w-full">
<h1 className="text-xl tracking-wide font-bold text-dark-gray dark:text-white flex items-center mb-2">
Update Cover
<span className="ml-1">
<Icons name="block-question" />
</span>
</h1>
<p className="text-base text-thin-light-gray mb-5">
Cover of at least Size
<span className="ml-1 text-dark-gray dark:text-white">
1170x920
</span>
.
</p>
<div className="flex justify-center">
<div className="w-full relative">
<img
src={coverImg}
alt=""
className="w-full h-[120px] rounded-lg overflow-hidden object-cover"
/>
<input
ref={coverImgInput}
onChange={(e) => coverImgChangHandler(e)}
type="file"
className="hidden"
/>
<div
onClick={browseCoverImg}
className="w-[32px] h-[32px] absolute -bottom-4 right-4 bg-dark-gray hover:bg-pink rounded-full cursor-pointer"
>
<svg
width="32"
height="32"
viewBox="0 0 32 32"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M16.5147 11.5C17.7284 12.7137 18.9234 13.9087 20.1296 15.115C19.9798 15.2611 19.8187 15.4109 19.6651 15.5683C17.4699 17.7635 15.271 19.9587 13.0758 22.1539C12.9334 22.2962 12.7948 22.4386 12.6524 22.5735C12.6187 22.6034 12.5663 22.6296 12.5213 22.6296C11.3788 22.6334 10.2362 22.6297 9.09365 22.6334C9.01498 22.6334 9 22.6034 9 22.536C9 21.4009 9 20.2621 9.00375 19.1271C9.00375 19.0746 9.02997 19.0109 9.06368 18.9772C10.4123 17.6249 11.7609 16.2763 13.1095 14.9277C14.2295 13.8076 15.3459 12.6913 16.466 11.5712C16.4884 11.5487 16.4997 11.5187 16.5147 11.5Z"
fill="white"
/>
<path
d="M20.9499 14.2904C19.7436 13.0842 18.5449 11.8854 17.3499 10.6904C17.5634 10.4694 17.7844 10.2446 18.0054 10.0199C18.2639 9.76139 18.5261 9.50291 18.7884 9.24443C19.118 8.91852 19.5713 8.91852 19.8972 9.24443C20.7251 10.0611 21.5492 10.8815 22.3771 11.6981C22.6993 12.0165 22.7105 12.4698 22.3996 12.792C21.9238 13.2865 21.4443 13.7772 20.9686 14.2717C20.9648 14.2792 20.9536 14.2867 20.9499 14.2904Z"
fill="white"
/>
</svg>
</div>
</div>
</div>
</div>
</div> </div>
</div> </div>
)) ))
@@ -351,7 +332,6 @@ export default function PersonalInfoTab({
: :
<div className="py-3 text-slate-500">Opps! something went wrong. Try Again Later!</div> <div className="py-3 text-slate-500">Opps! something went wrong. Try Again Later!</div>
} }
<div className="content-footer w-full"> <div className="content-footer w-full">
{requestStatus.message != '' && <p className={`text-center text-base ${requestStatus.status ? 'text-green-800' : 'text-red-600'}`}>{requestStatus.message}</p>} {requestStatus.message != '' && <p className={`text-center text-base ${requestStatus.status ? 'text-green-800' : 'text-red-600'}`}>{requestStatus.message}</p>}
<div className="w-full h-[120px] border-t border-light-purple dark:border-[#5356fb29] flex justify-end items-center"> <div className="w-full h-[120px] border-t border-light-purple dark:border-[#5356fb29] flex justify-end items-center">
@@ -370,16 +350,19 @@ export default function PersonalInfoTab({
<LoadingSpinner size='8' color='sky-blue' /> <LoadingSpinner size='8' color='sky-blue' />
: :
<button <button
type="button" type="submit"
className="w-[152px] h-[46px] flex justify-center items-center btn-gradient text-base rounded-full text-white" className="w-[152px] h-[46px] flex justify-center items-center btn-gradient text-base rounded-full text-white"
onClick={handleUpdateUser}
> >
Upadate Profile Update Profile
</button> </button>
} }
</div> </div>
</div> </div>
</div> </div>
</Form>
)
})}
</Formik>
</div> </div>
); );
} }