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

Commit

Permalink
feature: transfer user card functionality (#110)
Browse files Browse the repository at this point in the history
* feat(user-card): move user-card component from previuos branch

* fix(docs): change .MD to .md

* feat(and-more): add new component

* feat(and-more): add counter

* feat(and-more): {finaly} add counting of languages

* fix(user-card): names of files

* fix(user-card & and-more): delete comments

* fix(user-card): move inline styles to separate file

* fix(user-card): change props using + minor changes

* feat(user-card): move 'and-more' feature to badge-framework component

* feat(user-card): move 'and-more' feature to badge-languages component

* fix(user-card): and-more button size in badge-framework component

* fix(user-card): displaying of 2 languages

* fix(and-more): delete unused component

* fix(user-card): use css variables

* fix(user-card): delete inline styles and move to scss file

* fix(badge-framework): replace img tag with Image

* refactor(user-card): new polymorphic function to use render badges

* fix(user-card): all problems

* fix(user-card): delete unused part of code

* fix(user-card): linter

* fix(user-card): fix placement of elements

* feat(user-card): crown for leaders

* feat: add new logic for render langs and frameworks

* refactor: refactor

* refactor: refactor

* refactor: refactor

* refactor: refactor

* refactor: refactor scss

* refactor: refactor

* refactor: refactor

* feat: ✨ add animation for crown

* feat: ✨ add animation for card

* feat: ✨ add types

* feat: ✨ add types

* feat: ✨ add @teameights/types

* Delete node_modules directory

* fix: save changes

* fix: fix css

* refactor: refactor

* refactor: refactor

* fix(user-card): crown

* feat(user-card): hover effect

* feat(user-card): use entities instead of widgets

* feat(user-card): add controller for storybook

* feat(user-card): storybook params

* feat(user-card): add onClick param for useCallback hooks

* save changes

* feat(user-card): adjust badgeFrameworkLayoutConfig and Image component in card module

* feat(user-card): add hover effect and cursor pointer to user card component

* feat(user-card): add hover effect and cursor pointer to user card component

* feat(user-card): update UserCard component to display user's date of birth and role name

* feat(user-card): use generateMockUser function for default user in UserCardPreview story

* feat(user-card): update generateMockFileEntity to include random query parameter for image path 🚀

* feat(user-card): calculate and display user's age in UserCard component 🎂

* feat(user-card): add new mock data generation functions and update Home component to use them 🚀

* feat(user-card): update file paths and import styles to use consistent naming convention 🔄📦

* feat(user-card): add new logic for render langs and frameworks 🌐✨

* fix

* fix

* feat(user-card): restyle badge-language

* fix: adjust code to changes from merge

* fix(user-card): update user for storybook to match user type

* feat(user-card): add country flag icon

---------

Co-authored-by: Berezhnev Vladimir <[email protected]>
Co-authored-by: Sivritkin Dmitriy <[email protected]>
Co-authored-by: Romas Bitinas <[email protected]>
  • Loading branch information
4 people committed Dec 9, 2023
1 parent a3134f9 commit c00d1fe
Show file tree
Hide file tree
Showing 22 changed files with 576 additions and 31 deletions.
16 changes: 4 additions & 12 deletions .github/workflows/client.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ on:

jobs:
pipeline:
# Exclude renovate[bot] from triggering the workflow
if: github.actor != 'renovate[bot]'
runs-on: ubuntu-latest
strategy:
Expand All @@ -29,20 +28,14 @@ jobs:
uses: actions/setup-node@v3
with:
node-version: ${{matrix.node-version}}

- name: Cache Yarn dependencies
uses: actions/[email protected]
with:
path: ./client/node_modules
key: ${{ runner.os }}-yarn-${{ hashFiles('./client/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
cache: 'yarn'
cache-dependency-path: ./client/yarn.lock

- name: Install yarn and dependencies
working-directory: ./client
run: |
npm install --global yarn
yarn install --frozen-lockfile
yarn install --immutable
- name: Lint and Format
working-directory: ./client
Expand All @@ -52,8 +45,7 @@ jobs:
- name: Unit testing 💀💀
working-directory: ./client
run: |
yarn test:unit
run: yarn test:unit

- name: Build project
working-directory: ./client
Expand Down
2 changes: 1 addition & 1 deletion client/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

node_modules
.idea
.vscode
/storybook-static
Expand Down
5 changes: 1 addition & 4 deletions client/next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,14 @@ const path = require('path');

module.exports = {
images: {
domains: ['picsum.photos', 'source.unsplash.com'],
remotePatterns: [
{
protocol: 'https',
hostname: 's3.amazonaws.com',
port: '',
pathname: '/my-bucket/**',
},
{
protocol: 'https',
hostname: 'picsum.photos',
},
{
protocol: 'https',
hostname: 'flagcdn.com',
Expand Down
6 changes: 6 additions & 0 deletions client/src/app/styles/variables.scss
Original file line number Diff line number Diff line change
Expand Up @@ -108,16 +108,22 @@
--font-body-size-s: 14px;
--font-body-line-s: 120%;
--font-body-weight-s: 400;
--font-body-s: var(--font-body-weight-s) var(--font-body-size-s) / var(--font-body-line-s)
var(--font-rubik);

/* Body 2 -> Body M */
--font-body-size-m: 16px;
--font-body-line-m: 140%;
--font-body-weight-m: 400;
--font-body-m: var(--font-body-weight-s) var(--font-body-size-m) / var(--font-body-line-m)
var(--font-rubik);

/* Body 1 -> Body XL */
--font-body-size-l: 20px;
--font-body-line-l: 140%;
--font-body-weight-l: 400;
--font-body-l: var(--font-body-weight-l) var(--font-body-size-l) / var(--font-body-line-l)
var(--font-rubik);

/* Caption font */
--font-caption-size: 12px;
Expand Down
1 change: 1 addition & 0 deletions client/src/entities/user/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { UserCard } from './ui/user-card/user-card';
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
type BadgeFrameworkType = 'full' | 'half' | 'empty' | 'extra';
type BadgeFrameworkLayout = BadgeFrameworkType[];

interface badgeFrameworkLayoutConfig {
readonly default: Readonly<BadgeFrameworkLayout>;

readonly [badgeCount: number]: Readonly<BadgeFrameworkLayout>;
}

export const badgeFrameworkLayoutConfig: badgeFrameworkLayoutConfig = {
1: ['empty', 'full'],
2: ['full', 'full'],
3: ['half', 'half', 'full'],
4: ['half', 'half', 'half', 'half'],
default: ['half', 'half', 'half', 'extra'],
} as const;
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import styles from '../user-card/user-card.module.scss';
import { BadgeText } from '@/shared/ui';
import { badgeFrameworkLayoutConfig } from './frameworks-layout-config';

type BadgeFrameworksProps = {
frameworks: string[];
};

export const BadgeFrameworksLayout: React.FC<BadgeFrameworksProps> = ({ frameworks }) => {
const layout =
badgeFrameworkLayoutConfig[frameworks.length] || badgeFrameworkLayoutConfig.default;

const isOneFramework = frameworks.length === 1;

return (
<div className={styles.badgeContainer}>
{layout.map((size, index) => (
<BadgeText
className={styles[size]}
data={
size === 'extra' ? `+${frameworks.length - 3}` : frameworks[isOneFramework ? 0 : index]
}
key={frameworks[index]}
/>
))}
</div>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
type LanguageType = 'single' | 'more' | 'empty';
type LanguageLayout = LanguageType[];

interface LanguageLayoutConfig {
readonly default: Readonly<LanguageLayout>;

readonly [languageCount: number]: Readonly<LanguageLayout>;
}

export const languageLayoutConfig: LanguageLayoutConfig = {
1: ['single', 'empty'],
2: ['single', 'single'],
3: ['single', 'more'],
default: ['single', 'more'],
} as const;
20 changes: 20 additions & 0 deletions client/src/entities/user/ui/language-layout/language-layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import styles from '../user-card/user-card.module.scss';
import { BadgeIcon } from '@/shared/ui';
import { languageLayoutConfig } from './language-layout-config';

interface ProgrammingLanguagesProps {
languages: string[];
}

export const ProgrammingLanguagesLayout: React.FC<ProgrammingLanguagesProps> = ({ languages }) => {
const layout = languageLayoutConfig[languages.length] || languageLayoutConfig.default;

return (
<div className={styles.languagesContainer}>
{layout.map((type, index) => {
if (type === 'more') return <BadgeIcon key={index} data={`+${languages.length - 1}`} />;
return languages[index] && <BadgeIcon key={languages[index]} data={languages[index]} />;
})}
</div>
);
};
121 changes: 121 additions & 0 deletions client/src/entities/user/ui/user-card/user-card.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
@keyframes pulse {
0% {
transform: rotate(30deg) scale(1);
}
50% {
transform: rotate(30deg) scale(1.1);
}
100% {
transform: rotate(30deg) scale(1);
}
}

.card {
padding: 20px;
position: relative;
border-radius: 15px;
width: 100%;
max-width: 230px;
height: 280px;
background: var(--cards-color);
cursor: pointer;
box-sizing: border-box;
border: 1px solid transparent;
transition: all 0.25s ease;
transition-property: border, background, box-shadow;

&:hover {
border: 1px solid rgba(188, 202, 235, 0.4);
background: linear-gradient(
126deg,
rgba(184, 197, 229, 0.16) 10.31%,
rgba(188, 202, 235, 0.08) 91.99%
);
box-shadow: var(--usercard-shadow);
}
}

.header {
display: flex;
align-items: center;
}

.avatar {
position: relative;

.image {
border-radius: 5px;
}

.crown {
position: absolute;
top: -15%;
right: -15%;
transform: rotate(30deg);
animation: pulse 2s infinite;
}
}

.languagesContainer {
display: flex;
gap: 10px;
width: 100%;
justify-content: flex-end;
align-items: center;
align-self: stretch;
}

.content {
padding-top: 16px;
padding-bottom: 20px;
display: flex;
flex-direction: column;
column-gap: 8px;

.name {
font: var(--font-body-m);
display: flex;
align-items: center;
gap: 8px;
}

.role {
font: var(--font-body-s);
color: var(--grey-normal-color);
flex-basis: 34px;
display: -webkit-box;
overflow: hidden;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
}
}

.badgeContainer {
display: flex;
flex-wrap: wrap;
align-self: stretch;
height: 74px;
gap: 10px;
}

.empty {
visibility: hidden;
}

.full,
.framework {
flex: 1 1 100%;
}

.half {
flex: 1 1 calc(50% - 10px);
}

.extra {
flex: 1 1 calc(50% - 10px);
background: var(--grey-dark-color);
display: flex;
justify-content: center;
align-items: center;
border-radius: 5px;
}
91 changes: 91 additions & 0 deletions client/src/entities/user/ui/user-card/user-card.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import type { Meta, StoryObj } from '@storybook/react';
import { UserCard } from './user-card';
import { IUserResponse } from '@teameights/types';
import { generateMockUser } from '@/shared/lib/mock';

const defaultUser = generateMockUser();

// More on how to set up stories at: https://storybook.js.org/docs/react/writing-stories/introduction
const meta: Meta<typeof UserCard> = {
title: 'entities/User/UserCard',
component: UserCard,
tags: ['autodocs'],
argTypes: {
user: {
photo: { control: 'text' },
fullName: { control: 'text' },
programmingLanguages: { control: 'array' },
frameworks: { control: 'array' },
isLeader: { control: 'boolean' },
},
},
};
export default meta;
type Story = StoryObj<typeof UserCard>;

export const UserCardPreview: Story = {
args: {
user: defaultUser,
},
};

const user1 = {
...defaultUser,
skills: { programmingLanguages: ['JavaScript'], frameworks: ['Node.js'] },
isLeader: true,
} as unknown as IUserResponse;
export const UserCard_1variant = () => <UserCard user={user1} />;

const user2 = {
...defaultUser,
skills: {
programmingLanguages: ['JavaScript', 'TypeScript'],
frameworks: ['Node.js', 'React.js'],
},
isLeader: true,
} as unknown as IUserResponse;
export const UserCard_2variant = () => <UserCard user={user2} />;

const user3 = {
...defaultUser,
skills: {
programmingLanguages: ['JavaScript', 'TypeScript', 'Rust'],
frameworks: ['Node.js', 'React.js', 'MUI'],
},
isLeader: true,
} as unknown as IUserResponse;
export const UserCard_3variant = () => <UserCard user={user3} />;

const user4 = {
...defaultUser,
skills: {
programmingLanguages: ['JavaScript', 'TypeScript', 'Rust', 'Java'],
frameworks: ['Node.js', 'React.js', 'MUI', 'Vue.js'],
},
isLeader: true,
} as unknown as IUserResponse;
export const UserCard_4variant = () => <UserCard user={user4} />;

const user5 = {
...defaultUser,
skills: {
programmingLanguages: ['JavaScript', 'TypeScript', 'Rust', 'Java', 'PHP'],
frameworks: ['Node.js', 'React.js', 'MUI', 'Vue.js', 'Angular'],
},
isLeader: true,
} as unknown as IUserResponse;
export const UserCard_5variant = () => <UserCard user={user5} />;

const userWithoutPhoto = {
...defaultUser,
skills: {
programmingLanguages: ['JS', 'TS', 'Rust', 'Java', 'Php'],
frameworks: ['Node.js', 'React.js', 'MUI', 'Vue.js', 'Angular'],
},
fullName: 'John Doe',
isLeader: true,
} as unknown as IUserResponse;

userWithoutPhoto.photo = null;

export const UserCardWithImageFallback = () => <UserCard user={userWithoutPhoto} />;
Loading

2 comments on commit c00d1fe

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy preview for teameights ready!

✅ Preview
https://teameights-9evvyh71z-exortme1ster.vercel.app

Built with commit c00d1fe.
This pull request is being automatically deployed with vercel-action

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy preview for teameights-storybook ready!

✅ Preview
https://teameights-storybook-a08sdfnab-exortme1ster.vercel.app

Built with commit c00d1fe.
This pull request is being automatically deployed with vercel-action

Please sign in to comment.