Skip to content

Commit

Permalink
Show a form modal if the user doesn't have social media for the profile
Browse files Browse the repository at this point in the history
  • Loading branch information
sidiDev committed Dec 18, 2023
1 parent c3dc841 commit 1a37b31
Show file tree
Hide file tree
Showing 5 changed files with 196 additions and 4 deletions.
11 changes: 8 additions & 3 deletions app/account/details/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,9 @@ function Profile() {
<form onSubmit={handleSubmit} className="mt-4">
<div className="space-y-4">
<div>
<Label>Full name</Label>
<Label>Full name (required)</Label>
<Input
required
value={fullName}
onChange={e => {
setFullName((e.target as HTMLInputElement).value);
Expand All @@ -119,8 +120,9 @@ function Profile() {
<LabelError className="mt">{fullNameError}</LabelError>
</div>
<div>
<Label>Username</Label>
<Label>Username (required)</Label>
<Input
required
value={username}
onChange={e => {
setUsername((e.target as HTMLInputElement).value);
Expand All @@ -145,8 +147,10 @@ function Profile() {
)}
</div>
<div>
<Label>Social Media URL</Label>
<Label>Social Media URL (required)</Label>
<Input
required
placeholder="Twitter/Linkedin/Facebook or Any other social media"
value={socialMediaLink}
onChange={e => {
setSocialMediaLink((e.target as HTMLInputElement).value);
Expand Down Expand Up @@ -180,6 +184,7 @@ function Profile() {
<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);
Expand Down
2 changes: 2 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import ProgressBarClient from '@/components/ui/ProgressBarClient';
import ModalBannerCodeClient from '@/components/ui/ModalBannerCode/ModalBannerCodeClient';

import dynamic from 'next/dynamic';
import ProfileFormModal from '@/components/ui/ProfileFormModal';

const ChatWindow = dynamic(() => import('@/components/ui/ChatWindow'), { ssr: false });

Expand Down Expand Up @@ -113,6 +114,7 @@ export default async function RootLayout({ children }: { children: React.ReactNo
<ChatWindow />
<SupabaseProvider user={profile as Profile} session={session}>
<SupabaseListener serverAccessToken={session?.access_token} />
<ProfileFormModal isModalOpen={user && profile?.social_url ? false : true} />
<Banner />
<Navbar />
<ModalBannerCodeClient />
Expand Down
2 changes: 1 addition & 1 deletion components/ui/Modal/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default ({
variant = 'default',
className = '',
classNameContainer,
onCancel,
onCancel = () => {},
}: Props) => {
return isActive ? (
<div className="fixed w-full h-full inset-0 z-40 overflow-y-auto">
Expand Down
173 changes: 173 additions & 0 deletions components/ui/ProfileFormModal/ProfileFormModal.tsx
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;
12 changes: 12 additions & 0 deletions components/ui/ProfileFormModal/index.tsx
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>
);
};

0 comments on commit 1a37b31

Please sign in to comment.