import React, { useState, useRef } from 'react'; import styled from 'styled-components'; import { User } from 'shared/icons'; import Button from 'shared/components/Button'; import { useForm } from 'react-hook-form'; import ControlledInput from 'shared/components/ControlledInput'; const PasswordInput = styled(ControlledInput)` margin-top: 30px; margin-bottom: 0; `; const UserInfoInput = styled(ControlledInput)` margin-top: 30px; margin-bottom: 0; `; const FormError = styled.span` font-size: 12px; color: ${(props) => props.theme.colors.warning}; `; const ProfileContainer = styled.div` display: flex; align-items: center; margin-bottom: 2.2rem !important; `; const AvatarContainer = styled.div` width: 70px; height: 70px; border-radius: 50%; position: relative; cursor: pointer; display: inline-block; margin: 5px; margin-bottom: 1rem; margin-right: 1rem; `; const AvatarMask = styled.div<{ background: string }>` position: absolute; width: 100%; height: 100%; overflow: hidden; background: ${(props) => props.background}; border-radius: 50%; display: flex; align-items: center; justify-content: center; `; const AvatarImg = styled.img<{ src: string }>` display: block; width: 100%; height: 100%; `; const ActionButtons = styled.div` display: flex; flex-wrap: wrap; align-items: center; `; const UploadButton = styled(Button)` margin-right: 1rem; display: inline-block; `; const RemoveButton = styled(Button)` display: inline-block; `; const ImgLabel = styled.p` color: #c2c6dc; margin-top: 0.5rem; font-size: 12.25px; width: 100%; `; const AvatarInitials = styled.span` font-size: 32px; color: #fff; `; type AvatarSettingsProps = { onProfileAvatarChange: () => void; onProfileAvatarRemove: () => void; profile: ProfileIcon; }; const AvatarSettings: React.FC = ({ profile, onProfileAvatarChange, onProfileAvatarRemove }) => { return ( onProfileAvatarChange()} > {profile.url ? ( ) : ( {profile.initials} )} onProfileAvatarChange()}>Upload photo onProfileAvatarRemove()}> Remove Allowed JPG, GIF or PNG. Max size of 800kB ); }; const Container = styled.div` padding: 2.2rem; display: flex; width: 100%; position: relative; `; const TabNav = styled.div` float: left; width: 220px; height: 100%; display: block; position: relative; `; const TabNavContent = styled.ul` display: block; width: auto; border-bottom: 0 !important; border-right: 1px solid rgba(0, 0, 0, 0.05); `; const TabNavItem = styled.li` padding: 0.35rem 0.3rem; display: block; position: relative; `; const TabNavItemButton = styled.button<{ active: boolean }>` cursor: pointer; display: flex; align-items: center; padding-top: 10px !important; padding-bottom: 10px !important; padding-left: 12px !important; padding-right: 8px !important; width: 100%; position: relative; color: ${(props) => (props.active ? `${props.theme.colors.primary}` : '#c2c6dc')}; &:hover { color: ${(props) => props.theme.colors.primary}; } &:hover svg { fill: ${(props) => props.theme.colors.primary}; } `; const TabNavItemSpan = styled.span` text-align: left; padding-left: 9px; font-size: 14px; `; const TabNavLine = styled.span<{ top: number }>` left: auto; right: 0; width: 2px; height: 48px; transform: scaleX(1); top: ${(props) => props.top}px; background: linear-gradient( 30deg, ${(props) => props.theme.colors.primary}, ${(props) => props.theme.colors.primary} ); box-shadow: 0 0 8px 0 ${(props) => props.theme.colors.primary}; display: block; position: absolute; transition: all 0.2s ease; `; const TabContentWrapper = styled.div` margin-left: 1rem; position: relative; display: block; overflow: hidden; width: 100%; `; const TabContent = styled.div` position: relative; width: 100%; display: block; padding: 0; padding: 1.5rem; background-color: #10163a; border-radius: 0.5rem; `; const TabContentInner = styled.div``; const items = [{ name: 'General' }, { name: 'Change Password' }, { name: 'Info' }, { name: 'Notifications' }]; type NavItemProps = { active: boolean; name: string; tab: number; onClick: (tab: number, top: number) => void; }; const NavItem: React.FC = ({ active, name, tab, onClick }) => { const $item = useRef(null); return ( { if ($item && $item.current) { const pos = $item.current.getBoundingClientRect(); onClick(tab, pos.top); } }} > {name} ); }; const SettingActions = styled.div` display: flex; align-items: center; justify-content: flex-end; margin-top: 12px; `; const SaveButton = styled(Button)` margin-right: 1rem; display: inline-block; `; type SettingsProps = { onProfileAvatarChange: () => void; onProfileAvatarRemove: () => void; onChangeUserInfo: (data: UserInfoData, done: () => void) => void; onResetPassword: (password: string, done: () => void) => void; profile: TaskUser; }; type TabProps = { tab: number; currentTab: number; }; const Tab: React.FC = ({ tab, currentTab, children }) => { if (tab !== currentTab) { return null; } return {children}; }; type ResetPasswordTabProps = { onResetPassword: (password: string, done: () => void) => void; }; const ResetPasswordTab: React.FC = ({ onResetPassword }) => { const [active, setActive] = useState(true); const { register, handleSubmit, formState: { errors }, setError, reset, } = useForm<{ password: string; passwordConfirm: string }>(); const done = () => { reset(); setActive(true); }; return (
{ if (data.password !== data.passwordConfirm) { setError('password', { message: 'Passwords must match!', type: 'error' }); setError('passwordConfirm', { message: 'Passwords must match!', type: 'error' }); } else { onResetPassword(data.password, done); } })} > {errors.password && {errors.password.message}} {errors.passwordConfirm && {errors.passwordConfirm.message}} Save Change ); }; type UserInfoData = { fullName: string; bio: string; initials: string; email: string; }; type UserInfoTabProps = { profile: TaskUser; onProfileAvatarChange: () => void; onProfileAvatarRemove: () => void; onChangeUserInfo: (data: UserInfoData, done: () => void) => void; }; const EMAIL_PATTERN = /[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?/i; const INITIALS_PATTERN = /^[a-zA-Z]{2,3}$/i; const UserInfoTab: React.FC = ({ profile, onProfileAvatarRemove, onProfileAvatarChange, onChangeUserInfo, }) => { const [active, setActive] = useState(true); const { register, handleSubmit, formState: { errors }, } = useForm(); const done = () => { setActive(true); }; return ( <>
{ setActive(false); onChangeUserInfo(data, done); })} > {errors.fullName && {errors.fullName.message}} {errors.initials && {errors.initials.message}} {errors.email && {errors.email.message}} {errors.bio && {errors.bio.message}} Save Change ); }; const Settings: React.FC = ({ onProfileAvatarRemove, onProfileAvatarChange, onChangeUserInfo, onResetPassword, profile, }) => { const [currentTab, setTab] = useState(0); const [currentTop, setTop] = useState(0); const $tabNav = useRef(null); return ( {items.map((item, idx) => ( { if ($tabNav && $tabNav.current) { const pos = $tabNav.current.getBoundingClientRect(); setTab(tab); setTop(top - pos.top); } }} name={item.name} tab={idx} active={idx === currentTab} /> ))} ); }; export default Settings;