forked from MarsX-dev/devhunt
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Show a form modal if the user doesn't have social media for the profile
- Loading branch information
Showing
5 changed files
with
196 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
'use client'; | ||
|
||
import React, { type FormEventHandler, useEffect, useState } from 'react'; | ||
import UploadAvatar from '@/components/ui/UploadAvatar/UploadAvatar'; | ||
import Button from '@/components/ui/Button/Button'; | ||
import Input from '@/components/ui/Input'; | ||
import Label from '@/components/ui/Label/Label'; | ||
import Textarea from '@/components/ui/Textarea'; | ||
import { useSupabase } from '@/components/supabase/provider'; | ||
import { createBrowserClient } from '@/utils/supabase/browser'; | ||
import ProfileService from '@/utils/supabase/services/profile'; | ||
import LabelError from '@/components/ui/LabelError/LabelError'; | ||
import validateURL from '@/utils/validateURL'; | ||
import Alert from '../Alert'; | ||
|
||
function ProfileFormModal() { | ||
const { session, user } = useSupabase(); | ||
const userSession = session?.user; | ||
const profileService = new ProfileService(createBrowserClient()); | ||
const profile = profileService.getById(userSession?.id as string); | ||
|
||
const [isLoad, setLoad] = useState(false); | ||
const [fullName, setFullName] = useState(''); | ||
const [username, setUsername] = useState(''); | ||
const [websiteUrl, setWebsiteUrl] = useState(''); | ||
const [email, setEmail] = useState(''); | ||
const [isEmailTyping, setEmailTyping] = useState(false); | ||
const [about, setAbout] = useState(''); | ||
const [headline, setHeadLine] = useState(''); | ||
const [socialMediaLink, setSocialMediaLink] = useState(''); | ||
|
||
const [avatar, setAvatar] = useState('/user.svg'); | ||
const [selectedImage, setSelectedImage] = useState<File | null>(null); | ||
const [avatarPreview, setAvatarPreview] = useState<string>(''); | ||
|
||
const [fullNameError, setFullNameError] = useState(''); | ||
const [usernameError, setUsernameError] = useState(''); | ||
const [websiteUrlError, setWebsiteUrlError] = useState(''); | ||
const [aboutError, setAboutError] = useState(''); | ||
const [headlineError, setHeadLineError] = useState(''); | ||
const [socialMediaLinkError, setSocialMediaLinkError] = useState(''); | ||
|
||
useEffect(() => { | ||
profile.then(res => { | ||
setAvatar((user?.avatar_url as string) || '/user.svg'); | ||
setFullName(res?.full_name || ''); | ||
setUsername(res?.username || ''); | ||
setSocialMediaLink(res?.social_url || ''); | ||
setAbout(res?.about || ''); | ||
setWebsiteUrl(res?.website_url || ''); | ||
setEmail(userSession?.user_metadata.email || ''); | ||
setHeadLine(res?.headline || ''); | ||
}); | ||
}, []); | ||
|
||
const formValidator = () => { | ||
setFullNameError(''); | ||
setWebsiteUrlError(''); | ||
setSocialMediaLinkError(''); | ||
if (fullName.length < 2) setFullNameError('Please enter a correct full name'); | ||
if (username.length < 4) setUsernameError('the username should at least be 4 chars or more'); | ||
if (!socialMediaLink && !validateURL(socialMediaLink)) setSocialMediaLinkError('Please enter a valid URL'); | ||
else return true; | ||
}; | ||
|
||
const handleSubmit: FormEventHandler = async e => { | ||
e.preventDefault(); | ||
if (formValidator()) { | ||
setLoad(true); | ||
|
||
selectedImage ? await profileService.updateAvatar(userSession?.id as string, selectedImage) : null; | ||
profileService | ||
.update(userSession?.id as string, { | ||
full_name: fullName, | ||
username, | ||
about, | ||
headline, | ||
website_url: websiteUrl, | ||
social_url: socialMediaLink, | ||
}) | ||
.then(() => { | ||
setLoad(false); | ||
avatarPreview ? setAvatar(avatarPreview) : null; | ||
setAvatarPreview(''); | ||
setSelectedImage(null); | ||
window.location.reload(); | ||
}); | ||
} | ||
}; | ||
|
||
useEffect(() => { | ||
setTimeout(() => { | ||
setEmailTyping(false); | ||
}, 6000); | ||
}, [isEmailTyping]); | ||
|
||
return ( | ||
<> | ||
<div> | ||
<Alert | ||
variant="warning" | ||
context={"We need this to verify that you're a human so that we can monitor the voting and make sure there are no fake upvotes."} | ||
/> | ||
</div> | ||
<div className="mt-14"> | ||
<UploadAvatar | ||
avatarUrl={avatar} | ||
avatarPreview={avatarPreview} | ||
setSelectedImage={setSelectedImage} | ||
setAvatarPreview={setAvatarPreview} | ||
/> | ||
<form onSubmit={handleSubmit} className="mt-4"> | ||
<div className="space-y-4"> | ||
<div> | ||
<Label>Full name (required)</Label> | ||
<Input | ||
required | ||
value={fullName} | ||
onChange={e => { | ||
setFullName((e.target as HTMLInputElement).value); | ||
}} | ||
className="w-full mt-2" | ||
/> | ||
<LabelError className="mt">{fullNameError}</LabelError> | ||
</div> | ||
<div> | ||
<Label>Username (required)</Label> | ||
<Input | ||
required | ||
value={username} | ||
onChange={e => { | ||
setUsername((e.target as HTMLInputElement).value); | ||
}} | ||
className="w-full mt-2" | ||
/> | ||
<LabelError className="mt">{usernameError}</LabelError> | ||
</div> | ||
<div> | ||
<Label>Social Media URL (required)</Label> | ||
<Input | ||
value={socialMediaLink} | ||
placeholder="Twitter/Linkedin/Facebook or Any other social media" | ||
onChange={e => { | ||
setSocialMediaLink((e.target as HTMLInputElement).value); | ||
}} | ||
required | ||
className="w-full mt-2" | ||
/> | ||
<LabelError className="mt">{socialMediaLinkError}</LabelError> | ||
</div> | ||
<div> | ||
<Label>About (optional)</Label> | ||
<Textarea | ||
placeholder="Tell a bit about yourself. This page is gonna be visited by other developers." | ||
value={about} | ||
onChange={e => { | ||
setAbout((e.target as HTMLInputElement).value); | ||
}} | ||
className="w-full h-28 mt-2" | ||
/> | ||
<LabelError className="mt">{aboutError}</LabelError> | ||
</div> | ||
<Button isLoad={isLoad} className="flex justify-center w-full ring-offset-2 ring-orange-500 focus:ring-2 hover:bg-orange-400"> | ||
{isLoad ? 'Updating' : 'save'} | ||
</Button> | ||
</div> | ||
</form> | ||
</div> | ||
</> | ||
); | ||
} | ||
|
||
export default ProfileFormModal; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
'use client'; | ||
|
||
import Modal from '@/components/ui/Modal'; | ||
import ProfileFormModal from './ProfileFormModal'; | ||
|
||
export default ({ isModalOpen }: { isModalOpen: boolean }) => { | ||
return ( | ||
<Modal variant="custom" isActive={isModalOpen} onCancel={() => {}} className="max-w-2xl bg-slate-900"> | ||
<ProfileFormModal /> | ||
</Modal> | ||
); | ||
}; |