Skip to content
This repository has been archived by the owner on Mar 23, 2024. It is now read-only.

Feature/friends #143

Merged
merged 75 commits into from
Mar 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
441f7b3
feat: create friendship system
Ivan-Sai Dec 29, 2023
292ba7a
test: add e2e tests for friendship functionality
Ivan-Sai Jan 25, 2024
75853b1
wip: add basic profile layout
pupixipup Jan 27, 2024
903345c
feat: add profile list icons
pupixipup Feb 3, 2024
2eddf71
feat: add icons
pupixipup Feb 3, 2024
cc5b0f2
feat: add icons
pupixipup Feb 3, 2024
03ea13b
feat: add social links
pupixipup Feb 3, 2024
84be41b
feat: add logo
pupixipup Feb 3, 2024
8000501
fix: layout behind aside menu
pupixipup Feb 3, 2024
67c0f50
feat: add back button
pupixipup Feb 3, 2024
1247de8
feat: add age
pupixipup Feb 3, 2024
6ad7909
fix: add migration
Ivan-Sai Feb 3, 2024
0bca708
Merge remote-tracking branch 'origin/feature/friends' into feature/fr…
Ivan-Sai Feb 3, 2024
a69cc09
fix: remove profile id at the button link
pupixipup Feb 3, 2024
0a11b94
Merge branch 'feature/friends' of https://github.com/nmashchenko/team…
pupixipup Feb 3, 2024
22ba88d
fix: toggle leader icon based on fetch data
pupixipup Feb 3, 2024
997eddc
feat: add empty placeholder for about section
pupixipup Feb 4, 2024
4b78a22
update: add check friendship status
Ivan-Sai Feb 6, 2024
a693d7a
Merge remote-tracking branch 'origin/feature/friends' into feature/fr…
Ivan-Sai Feb 6, 2024
5027de5
feat: add [username] to the path
pupixipup Feb 6, 2024
cd96263
Revert "feat: add [username] to the path"
pupixipup Feb 6, 2024
a4bddc0
fix: change route to the profile page
pupixipup Feb 6, 2024
91136ef
feat: add empty state
pupixipup Feb 6, 2024
a32e3bb
update: reworked notification update
Ivan-Sai Feb 9, 2024
bd18d32
Merge remote-tracking branch 'origin/feature/friends' into feature/fr…
Ivan-Sai Feb 9, 2024
93a278a
update: updated friendship delete
Ivan-Sai Feb 9, 2024
71ddf1a
fix: incorrect image reference
pupixipup Feb 9, 2024
793d96f
fix: case when links are missing
pupixipup Feb 9, 2024
c059777
fix: minor ui changes
pupixipup Feb 9, 2024
8902554
refactor: run prettier
pupixipup Feb 10, 2024
2dd25d1
feat: add skills (except projects & tournaments)
pupixipup Feb 10, 2024
79b5535
feat: add friends button logics
pupixipup Feb 10, 2024
6bc0a2a
feat: merged develop
nmashchenko Feb 11, 2024
b883435
refactor: remove eslint errors
pupixipup Feb 11, 2024
8da9a84
fix: back icon position
pupixipup Feb 11, 2024
c714b72
refactor: run Prettier
pupixipup Feb 14, 2024
7bb4e0b
fix: specialty field to match updated type
pupixipup Feb 14, 2024
00cec74
fix: skills to match updated structure
pupixipup Feb 14, 2024
2df2db2
fix: replace useGetMe with useGetUser
pupixipup Feb 14, 2024
91d8fe1
feat: add Friendship seed
pupixipup Feb 15, 2024
f5586dd
fix: remove nav placeholder shrinking
pupixipup Feb 16, 2024
e146c36
fix: profile nav button path
pupixipup Feb 16, 2024
e9322e7
fix: full navbar size
pupixipup Feb 16, 2024
e4d2c29
wip: add list of friends
pupixipup Feb 16, 2024
c2258fd
feat: add friends modal
pupixipup Feb 17, 2024
e4b1fed
feat: add responsiveness
pupixipup Feb 17, 2024
f050cbd
refactor: move logics to page.tsx
pupixipup Feb 18, 2024
7b5b29e
feat: add friend removal
pupixipup Feb 18, 2024
ad20a46
refactor: remove unused import
pupixipup Feb 18, 2024
af6fca3
fix: end -> flex-end
pupixipup Feb 18, 2024
7ae3caf
refactor: split ui to folders
pupixipup Feb 18, 2024
ed44a82
fix: remove icon overlay
pupixipup Feb 18, 2024
640b972
fix: back icon position
pupixipup Feb 18, 2024
3333128
fix: small updates
nmashchenko Feb 18, 2024
a881293
Merge branch 'feature/friends' of https://github.com/nmashchenko/team…
nmashchenko Feb 18, 2024
f69e679
fix: prettier
nmashchenko Feb 18, 2024
d20b3f9
fix: backend lint
nmashchenko Feb 18, 2024
da0cc21
update: added username check
Ivan-Sai Feb 19, 2024
28693d9
Merge remote-tracking branch 'origin/feature/friends' into feature/fr…
Ivan-Sai Feb 19, 2024
b788340
update: added username check
Ivan-Sai Feb 19, 2024
58664e0
update: updated username check
Ivan-Sai Feb 22, 2024
76b4ff6
feat: friend button states
pupixipup Feb 23, 2024
71b52f5
fix: display correct skills
pupixipup Feb 23, 2024
ea02298
refactor: apply prettier
pupixipup Feb 23, 2024
4db1416
feat: add friend button (at user modal)
pupixipup Feb 23, 2024
b5e9f4c
feat: add friend notification
pupixipup Feb 24, 2024
86b5f19
feat: add profile link to user modal
pupixipup Mar 3, 2024
44f4bf9
refactor: add friend notification interface
pupixipup Mar 3, 2024
88d2ae3
feat: add width prop to friend btn
pupixipup Mar 3, 2024
9ed1ebd
feat: add friend button to infoModal
pupixipup Mar 3, 2024
d8fe188
feat:
pupixipup Mar 3, 2024
169012d
fix: fixed friendship status receiving
Ivan-Sai Mar 4, 2024
c2262bb
Merge remote-tracking branch 'origin/feature/friends' into feature/fr…
Ivan-Sai Mar 4, 2024
da969bb
fix: cleanup
Ivan-Sai Mar 4, 2024
7a99515
fix: generation
nmashchenko Mar 9, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 55 additions & 0 deletions client/src/app/(main)/[username]/profile/layout.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@

.container {
display: flex;
width: 100%;
height: 100%;
position: relative;
@media (max-width: 790px) {
position: unset;
}
.body {
width: 100%;
}
}

.back {
position: absolute;

left: 0;
display: flex;
align-items: center;
gap: 6px;
&:hover {
opacity: .7;
transition: .3s;
}

@media (max-width: 790px) {
top: 46px;
right: 15px;
left: unset;
}
}

.profile_row {
@media (max-width: 1045px) {
flex-direction: column;
width: 100%;
& > div {
width: 100%;
}
}
}

.sm_card {
width: 40%;
}

.lg_card {
width: 60%;
}

.list_card {
width: 40%;
gap: 18px;
}
24 changes: 24 additions & 0 deletions client/src/app/(main)/[username]/profile/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
'use client';
import styles from './layout.module.scss';
import { Flex, Typography } from '@/shared/ui';
import { ArrowLeftIcon, LogoBig } from '@/shared/assets';
import { useRouter } from 'next/navigation';

export default function Layout({ children }: { children: React.ReactNode }) {
const router = useRouter();

return (
<div className={styles.container}>
<Flex direction={'column'} width={'100%'} gap={'30px'}>
<button onClick={router.back} className={styles.back}>
<ArrowLeftIcon />
<Typography>Back</Typography>
</button>
<Flex justify='center'>
<LogoBig />
</Flex>
{children}
</Flex>
</div>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { createContext } from 'react';

export const ProfileContext = createContext(false);
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { useGetUsers } from '@/entities/session';
import { IUserResponse } from '@teameights/types';

export const useGetUserByName = (username: string): { data: IUserResponse | undefined } => {
const users = useGetUsers(JSON.stringify({ username: username }));

return { data: users?.data?.pages[0]?.data[0] };
};
46 changes: 46 additions & 0 deletions client/src/app/(main)/[username]/profile/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use client';
import styles from './layout.module.scss';
import { useGetMe } from '@/entities/session';
import { Header } from './ui/header/header';
import { CardSkeleton, Flex } from '@/shared/ui';
import { List } from './ui/list/list';
import { About } from './ui/about/about';
import { useParams } from 'next/navigation';
import { Friends } from './ui/friends/friends';
import { Fields } from './ui/fields/fields';
import { useGetUserByName } from './lib/useGetUserByName';
import { ProfileContext } from './lib/profile-context';

export default function Page() {
const { data: me } = useGetMe();
const { username } = useParams();
const { data: user } = useGetUserByName(username as string);
const isMyProf = me?.username === username;

let body = (
<Flex direction='column' gap='30px'>
<CardSkeleton borderRadius={15} width={'100%'} height={'227px'} />
<CardSkeleton borderRadius={15} width={'100%'} height={'227px'} />
</Flex>
);

if (user) {
body = (
<>
<Header />
<Flex padding='0 0 48px 0' direction='column' gap='30px'>
<Flex className={styles.profile_row} gap='30px'>
<List />
<About />
</Flex>
<Flex className={styles.profile_row} gap='30px'>
<Friends />
<Fields />
</Flex>
</Flex>
</>
);
}

return <ProfileContext.Provider value={isMyProf}> {body} </ProfileContext.Provider>;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.container {

}
58 changes: 58 additions & 0 deletions client/src/app/(main)/[username]/profile/ui/about/about.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { Card } from '../card/card';
import { Flex, Typography } from '@/shared/ui';
import { GithubIcon } from '@/shared/assets/icons/github-icon';
import { BehanceIcon } from '@/shared/assets/icons/behance';
import { TelegramIcon } from '@/shared/assets/icons/telegram';
import { LinkedinIcon } from '@/shared/assets/icons/linkedin';
import { useParams } from 'next/navigation';
import { useGetUserByName } from '../../lib/useGetUserByName';
import styles from '../../layout.module.scss';

export const About = () => {
const { username } = useParams();
const { data: user } = useGetUserByName(username as string);

const linksPresent = user?.links && Object.keys(user.links).length;
const descPresent = typeof user?.description === 'string';
return (
<Card className={styles.lg_card}>
<Flex direction='column' gap='24px' height='100%'>
<Typography size={'heading_s'} color={'greenBright'}>
About
</Typography>
{!descPresent && (
<Typography size={'body_s'} color={'greyNormal'}>
No description added.
</Typography>
)}
<Flex flex={1}>
{descPresent && <Typography size={'body_s'}>{user?.description}</Typography>}
</Flex>
{linksPresent && (
<Flex align={'center'} gap={24}>
{user?.links?.github && (
<a target='_blank' href={user.links.github}>
<GithubIcon width={28} />
</a>
)}
{user?.links?.behance && (
<a target='_blank' href={user.links.behance}>
<BehanceIcon width={28} />
</a>
)}
{user?.links?.telegram && (
<a target='_blank' href={user.links.telegram}>
<TelegramIcon width={28} />
</a>
)}
{user?.links?.linkedIn && (
<a target='_blank' href={user.links.linkedIn}>
<LinkedinIcon width={28} />
</a>
)}
</Flex>
)}
</Flex>
</Card>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.card {
background: rgba(26, 28, 34, 1);
border-radius: 15px;
overflow: hidden;
padding: 32px;
}
14 changes: 14 additions & 0 deletions client/src/app/(main)/[username]/profile/ui/card/card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ReactNode } from 'react';
import styles from './card.module.scss';
import clsx from 'clsx';

interface CardProps {
children: ReactNode;
className?: string;
borderRadius?: string;
}

export const Card = ({ children, className }: CardProps) => {
const cls = clsx(styles.card, className);
return <div className={cls}>{children}</div>;
};
35 changes: 35 additions & 0 deletions client/src/app/(main)/[username]/profile/ui/fields/education.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Flex, Typography } from '@/shared/ui';
import { useParams } from 'next/navigation';
import { useGetUserByName } from '../../lib/useGetUserByName';

export const Education = () => {
const { username } = useParams();
const { data: user } = useGetUserByName(username as string);
const universities = user?.universities;
if (!universities) return <Typography>No information</Typography>;
return (
<Flex gap='24px' direction='column'>
{universities.map((education, i) => {
const start = new Date(education.admissionDate).getFullYear();
const end = education.graduationDate
? new Date(education.graduationDate).getFullYear()
: 'Present';
return (
<Flex key={i} width={'100%'} justify={'space-between'}>
<Flex gap={'8px'} direction={'column'}>
<Typography size={'body_m'}>
{education.name ?? (education as unknown as { university: string }).university}
</Typography>
<Typography color={'greyNormal'} size={'body_s'}>
{education.degree} in {education.major}
</Typography>
</Flex>
<Typography>
{start} - {end}
</Typography>
</Flex>
);
})}
</Flex>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
.selected {
border-bottom: 1px solid #5bd424;
}

.field_text {
transition: 0.3s;
transition-property: color;
}

.fields_container {
min-height: 150px;
}

.nav_bar {
overflow-x: auto;
}
46 changes: 46 additions & 0 deletions client/src/app/(main)/[username]/profile/ui/fields/fields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Card } from '../card/card';
import { Flex, Typography } from '@/shared/ui';
import { useState } from 'react';
import styles from './fields.module.scss';
import { Skills } from './skills';
import { WorkExperience } from './work-experience';
import { Education } from './education';
import layoutStyles from '../../layout.module.scss';
export const Fields = () => {
const [field, setField] = useState<keyof typeof fields>('Skills');

const fields = {
Skills: <Skills />,
Projects: null,
'Work experience': <WorkExperience />,
Education: <Education />,
Tournaments: null,
};

return (
<Card className={layoutStyles.lg_card}>
<Flex direction='column' gap='24px' className={styles.fields_container}>
<Flex className={styles.nav_bar} gap='16px'>
{Object.keys(fields).map(key => {
const classProps = field === key ? { className: styles.selected } : {};
return (
<button
onClick={() => setField(key as keyof typeof fields)}
{...classProps}
key={key}
>
<Typography
className={styles.field_text}
color={field === key ? 'greenBright' : 'greyNormal'}
>
{key}
</Typography>
</button>
);
})}
</Flex>
{fields[field]}
</Flex>
</Card>
);
};
36 changes: 36 additions & 0 deletions client/src/app/(main)/[username]/profile/ui/fields/skills.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { BadgeText, Flex, Typography } from '@/shared/ui';
import { useGetUserByName } from '../../lib/useGetUserByName';
import { useParams } from 'next/navigation';
import { BadgeIcon } from '@/shared/ui';

export const Skills = () => {
const { username } = useParams();
const { data: user } = useGetUserByName(username as string);
pupixipup marked this conversation as resolved.
Show resolved Hide resolved
const skills = {
coreTools: {
badge: ({ data }: { data: string }) => <BadgeIcon data={data} isActive={true} />,
title: 'Core Tools',
},
additionalTools: {
badge: BadgeText,
title: 'Additional Tools',
},
};
return (
<Flex gap='24px' direction='column'>
{user!.skills &&
Object.entries(skills).map(skill => {
const skillName = skill[0] as keyof typeof skills;
const Badge = skills[skillName].badge;
return (
<Flex key={skillName} direction='column' gap='8px'>
<Typography>{skills[skillName].title}</Typography>
<Flex wrap='wrap' gap='8px'>
{user?.skills![skillName]?.map((lang: string) => <Badge key={lang} data={lang} />)}
</Flex>
</Flex>
);
})}
</Flex>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { Flex, Typography } from '@/shared/ui';
import { useParams } from 'next/navigation';
import { useGetUserByName } from '../../lib/useGetUserByName';
export const WorkExperience = () => {
const { username } = useParams();
const { data: user } = useGetUserByName(username as string);
const jobs = user?.jobs;
return (
<Flex gap='24px' direction='column'>
{jobs?.map((job, i: number) => {
const start = new Date(job.startDate).getFullYear();
const end = job.endDate ? new Date(job.endDate).getFullYear() : 'Present';
return (
<Flex key={i} width={'100%'} justify={'space-between'}>
<Flex gap={'8px'} direction={'column'}>
<Typography size={'body_m'}>{job.company}</Typography>
<Typography color={'greyNormal'} size={'body_s'}>
{job.title}
</Typography>
</Flex>
<Typography>
{start} - {end}
</Typography>
</Flex>
);
})}
</Flex>
);
};
Loading
Loading