Skip to content

Commit

Permalink
Redesign categories and subjects (#2040)
Browse files Browse the repository at this point in the history
* Redesign categories and subjects

* update font weight

* create getValidatedHexColor function

* update delete icon
  • Loading branch information
YaroslavChuiko authored Jul 5, 2024
1 parent 8b4752c commit 67208b6
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 81 deletions.
4 changes: 2 additions & 2 deletions src/constants/translations/en/edit-profile.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@
"cancelBtn": "Cancel",
"submitBtn": "Delete"
},
"mainStudyCategory": "Main Study Category",
"subject": "Subject",
"mainStudyCategory": "Main study category",
"subject": "The category subject(s)",
"proficiencyLevels": "Proficiency Levels",
"editCategoryBtn": "Edit category",
"deleteCategoryBtnDisabledTooltip": "You have opened cooperation(s)/offers with this category.\nPlease close it before deactivation",
Expand Down
2 changes: 1 addition & 1 deletion src/constants/translations/ua/edit-profile.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"submitBtn": "Видалити"
},
"mainStudyCategory": "Основна навчальна категорія",
"subject": "Предмет",
"subject": "Предмет(и) категорії",
"proficiencyLevels": "Рівні кваліфікації",
"editCategoryBtn": "Редагувати",
"deleteCategoryBtnDisabledTooltip": "Ви розпочали співпрацю(і)/пропозицію. з цією категорією.\nБудь ласка, закрийте її перед деактивацією",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { TypographyVariantEnum } from '~/types'
import palette from '~/styles/app-theme/app.pallete'
import { alpha, darken } from '@mui/material'

const { Body2, Overline, Caption } = TypographyVariantEnum

Expand All @@ -8,10 +9,9 @@ export const styles = {
border: `1px solid ${palette.primary[300]}`,
display: 'flex',
flexDirection: 'column',
gap: 3,
gap: 2.5,
borderRadius: 1,
px: 2,
py: 4
p: 3
},
createBtnContainer: {
my: 3
Expand All @@ -33,52 +33,48 @@ export const styles = {
},
deleteButton: {
svg: {
fill: palette.primary[700]
fill: palette.primary[900],
width: '20px',
height: '20px'
},
'&:disabled': { svg: { fill: palette.primary[200] } }
}
},
cards: {
display: 'flex',
flexDirection: 'column',
gap: 3
},
divider: {
my: 1
},
subjects: {
root: {
display: 'flex',
flexDirection: 'column',
columnGap: 3,
rowGap: 2
subjectChipLabel: (color: string) => ({
typography: Overline,
fontWeight: '500',
lineHeight: 1.2,
color: darken(color, 0.6)
}),
subjectChip: (color: string) => ({
backgroundColor: alpha(color, 0.6)
}),
categoryIcon: (color: string) => ({
width: '24px',
height: '24px',
color: color
}),
description: {
grid: {
m: 0,
display: 'grid',
gridTemplateColumns: { xs: '1fr', md: 'auto 1fr' },
gridTemplateRows: 'minmax(24px, auto)',
rowGap: 2,
columnGap: 3
},
item: {
display: 'flex',
flexDirection: 'column',
columnGap: 1,
rowGap: 2
}
},
card: {
root: {
m: 0
label: {
typography: Body2,
color: palette.basic.blueGray,
lineHeight: '24px',
alignSelf: 'start'
},
item: {
value: {
typography: Body2,
display: 'flex',
flexDirection: { xs: 'column', md: 'row' },
m: 0,
columnGap: 3,
rowGap: 1,
label: {
flex: 1,
typography: Overline,
lineHeight: '20px'
},
value: {
flex: 2.5,
typography: Body2
}
alignItems: 'center',
flexWrap: 'wrap',
gap: '12px'
}
}
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,24 @@
import Box from '@mui/material/Box'
import Divider from '@mui/material/Divider'
import IconButton from '@mui/material/IconButton'
import Typography from '@mui/material/Typography'
import Tooltip from '@mui/material/Tooltip'
import { FC } from 'react'
import DeleteIcon from '@mui/icons-material/Delete'
import { FC, ReactNode } from 'react'
import { useTranslation } from 'react-i18next'
import AppButton from '~/components/app-button/AppButton'
import AppChip from '~/components/app-chip/AppChip'
import { getCategoryIcon } from '~/services/category-icon-service'
import {
ButtonVariantEnum,
ComponentEnum,
PositionEnum,
UserMainSubject,
OpenProfessionalCategoryModalHandler
OpenProfessionalCategoryModalHandler,
SizeEnum
} from '~/types'
import DeleteIcon from '@mui/icons-material/Delete'
import useConfirm from '~/hooks/use-confirm'
import { styles } from '~/containers/edit-profile/professional-info-tab/professional-category/ProfessionalCategory.styles'
import { getValidatedHexColor } from '~/utils/get-validated-hex-color'

interface ProfessionalCategoryProps {
item: UserMainSubject
Expand Down Expand Up @@ -51,40 +54,50 @@ const ProfessionalCategory: FC<ProfessionalCategoryProps> = ({
})
}

const CardItem = ({
const handleEditButtonClick = () => {
openProfessionalCategoryModal(item)
}

const DescriptionItem = ({
label,
children
}: {
label: string
children: string
children: ReactNode
}) => {
return (
<Box sx={styles.card.item}>
<Typography component={ComponentEnum.Dt} sx={styles.card.item.label}>
<>
<Typography component={ComponentEnum.Dt} sx={styles.description.label}>
{label}:
</Typography>
<Typography component={ComponentEnum.Dd} sx={styles.card.item.value}>
<Typography component={ComponentEnum.Dd} sx={styles.description.value}>
{children}
</Typography>
</Box>
</>
)
}

const categoryColor = getValidatedHexColor(item.category.appearance.color)
const CategoryIcon = getCategoryIcon(item.category.appearance.icon)

const Subjects = item.subjects.map((subject) => (
<Box key={subject._id} sx={styles.subjects.item}>
<CardItem label={t('editProfilePage.profile.professionalTab.subject')}>
{subject.name}
</CardItem>
</Box>
<AppChip
key={subject._id}
labelSx={styles.subjectChipLabel(categoryColor)}
sx={styles.subjectChip(categoryColor)}
>
{subject.name}
</AppChip>
))

return (
<Box sx={styles.root}>
<Box sx={styles.toolbar.root}>
<Box sx={styles.toolbar.buttonGroup}>
<AppButton
onClick={() => openProfessionalCategoryModal(item)}
variant={ButtonVariantEnum.ContainedLight}
onClick={handleEditButtonClick}
size={SizeEnum.Medium}
variant={ButtonVariantEnum.Tonal}
>
{t('editProfilePage.profile.professionalTab.editCategoryBtn')}
</AppButton>
Expand All @@ -100,26 +113,28 @@ const ProfessionalCategory: FC<ProfessionalCategoryProps> = ({
)
}
>
<span>
<IconButton
data-testid='delete-professional-category-button'
disabled={item.isDeletionBlocked}
onClick={handleDeleteButtonClick}
sx={styles.toolbar.deleteButton}
>
<DeleteIcon />
</IconButton>
</span>
<IconButton
data-testid='delete-professional-category-button'
disabled={item.isDeletionBlocked}
onClick={handleDeleteButtonClick}
sx={styles.toolbar.deleteButton}
>
<DeleteIcon />
</IconButton>
</Tooltip>
</Box>
<Box component={ComponentEnum.Dl} sx={styles.card.root}>
<CardItem
<Box component={ComponentEnum.Dl} sx={styles.description.grid}>
<DescriptionItem
label={t('editProfilePage.profile.professionalTab.mainStudyCategory')}
>
<CategoryIcon sx={styles.categoryIcon(categoryColor)} />
{item.category.name}
</CardItem>
<Divider sx={styles.divider} />
<Box sx={styles.subjects.root}>{Subjects}</Box>
</DescriptionItem>
<DescriptionItem
label={t('editProfilePage.profile.professionalTab.subject')}
>
{Subjects}
</DescriptionItem>
</Box>
</Box>
)
Expand Down
4 changes: 2 additions & 2 deletions src/types/edit-profile/interfaces/editProfile.interfaces.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {
CategoryNameInterface,
CategoryInterface,
SubjectNameInterface,
UpdatedPhoto
} from '~/types/common/common.index'
Expand All @@ -16,7 +16,7 @@ export interface EditProfileForm
}

export interface ProfessionalCategory {
category: CategoryNameInterface
category: Pick<CategoryInterface, '_id' | 'name' | 'appearance'>
subjects: SubjectNameInterface[]
}

Expand Down
11 changes: 11 additions & 0 deletions src/utils/get-validated-hex-color.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import palette from '~/styles/app-theme/app.pallete'

const HEX_COLOR_PATTERN = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i

export const getValidatedHexColor = (
color: string,
fallbackColor: string = palette.success[500]
): string => {
const isValidHex = HEX_COLOR_PATTERN.test(color)
return isValidHex ? color : fallbackColor
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,28 @@ const mockedHandleDelete = vi.fn()

const categoryWithSubjects = {
_id: '648850c4fdc2d1a130c24aea',
category: { _id: '64884f21fdc2d1a130c24ac0', name: 'Music' },
category: {
_id: '64884f21fdc2d1a130c24ac0',
name: 'Music',
appearance: {
color: '#FFD700',
icon: 'MusicNoteIcon'
}
},
subjects: [{ _id: '64885108fdc2d1a130c24af9', name: 'Guitar' }],
isDeletionBlocked: false
}

const blockedCategory = {
_id: '648850c4fdc2d1a130c24aea',
category: { _id: '64884f21fdc2d1a130c24ac0', name: 'Music' },
category: {
_id: '64884f21fdc2d1a130c24ac0',
name: 'Music',
appearance: {
color: '#FFD700',
icon: 'MusicNoteIcon'
}
},
subjects: [{ _id: '64885108fdc2d1a130c24af9', name: 'Guitar' }],
isDeletionBlocked: true
}
Expand Down
32 changes: 32 additions & 0 deletions tests/unit/utils/get-validated-hex-color.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { getValidatedHexColor } from '~/utils/get-validated-hex-color'
import palette from '~/styles/app-theme/app.pallete'

describe('getValidatedHexColor', () => {
it('should return the color if it is a valid 6-digit hex', () => {
const color = '#FFFFFF'
expect(getValidatedHexColor(color)).toBe(color)
})

it('should return the color if it is a valid 3-digit hex', () => {
const color = '#FFF'
expect(getValidatedHexColor(color)).toBe(color)
})

it('should return the fallback color if the input is not a valid hex color', () => {
const invalidColor = '#WWWWWW'
expect(getValidatedHexColor(invalidColor)).toBe(palette.success[500])
})

it('should return the fallback color if the input is an empty string', () => {
const invalidColor = ''
expect(getValidatedHexColor(invalidColor)).toBe(palette.success[500])
})

it('should return the custom fallback color if the input is not a valid hex color', () => {
const invalidColor = '#WWWWWW'
const customFallbackColor = '#FF5733'
expect(getValidatedHexColor(invalidColor, customFallbackColor)).toBe(
customFallbackColor
)
})
})

0 comments on commit 67208b6

Please sign in to comment.