Skip to content

Commit

Permalink
feat(tp): pagination for browse jobseekers page (#915)
Browse files Browse the repository at this point in the history
* Install & configure TailwindCSS, wip

* Fix tailwind styles not applying for TP platform

* Setup shadcn/ui, wip

* Setup shadcn/ui, wip

* Setup shadcn/ui CLI

* Fix TailwindCSS & shadcn/ui configuration

* Add Paginate component and implement pagination, wip

* Add new icons, update chevron icon in diff components, replace radix-ui icons in pagination.tsx

* Implement pagination, wip

* Fix pagination implementation

* Fix console warnings

* Fix displaying pagination

* Fix pagination for favorited jobseeker profiles

* Style pagination items

* Fix location usage in LoggedIn.tsx for TP

* Consolidate styles in global.scss in shared-atomic-design-components library to share across our apps; remove duplicated style files

* Remove TailwindCSS testing code

* Remove TailwindCSS testing code

* Fix workspace.json and yarn.lock files

* Fix yarn.lock file

* Remove comments

* Fix styling of the pagination component

* Update the README.md file in libs/shared-shadcn-ui-components

* Fixes according to the PR comments

* Fix the component's name

* Update README file following the PR comments

* Rename the cn function to classNames, update README

* Update README file

* Refactor

* Fix a typo
  • Loading branch information
katamatata authored Sep 5, 2024
1 parent 100f570 commit d3dfac8
Show file tree
Hide file tree
Showing 26 changed files with 425 additions and 88 deletions.
8 changes: 4 additions & 4 deletions apps/redi-connect/src/components/organisms/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ const RediFooter = () => {
{t('footer.support')}
</Element>
<Element renderAs="ul">
{supportLinks.map((link) => (
<Element renderAs="li" key={link.url}>
{supportLinks.map((link, index) => (
<Element renderAs="li" key={`${link.url}-${index}`}>
<Element
renderAs="a"
href={link.url}
Expand All @@ -114,8 +114,8 @@ const RediFooter = () => {
{t('footer.legal')}
</Element>
<Element renderAs="ul">
{legalLinks.map((link) => (
<Element renderAs="li" key={link.url}>
{legalLinks.map((link, index) => (
<Element renderAs="li" key={`${link.url}-${index}`}>
<Element
renderAs="a"
href={link.url}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ const ApplicationCard = ({ application }: Props) => {

<Columns.Column className="application-card-dropdown">
<Icon
icon="chevron"
icon="chevronDown"
size="small"
className={classnames({ 'icon--rotate': showDetails })}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ function MobileApplicationCard({ application }: Props) {
</Columns.Column>
<Columns.Column className="mobile-application-card-dropdown">
<Icon
icon="chevron"
icon="chevronDown"
size="small"
className={classnames({ 'icon--rotate': showDetails })}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export function AccordionForm({
</Columns.Column>
<Columns.Column narrow>
<Icon
icon="chevron"
icon="chevronDown"
size="small"
className={classnames({ 'icon--rotate': isOpen })}
/>
Expand Down
8 changes: 4 additions & 4 deletions apps/redi-talent-pool/src/components/organisms/Footer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ const RediFooter = () => {
{t('footer.support')}
</Element>
<Element renderAs="ul">
{supportLinks.map((link) => (
<Element renderAs="li" key={link.url}>
{supportLinks.map((link, index) => (
<Element renderAs="li" key={`${link.url}-${index}`}>
<Element
renderAs="a"
href={link.url}
Expand All @@ -120,8 +120,8 @@ const RediFooter = () => {
{t('footer.legal')}
</Element>
<Element renderAs="ul">
{legalLinks.map((link) => (
<Element renderAs="li" key={link.url}>
{legalLinks.map((link, index) => (
<Element renderAs="li" key={`${link.url}-${index}`}>
<Element
renderAs="a"
href={link.url}
Expand Down
2 changes: 2 additions & 0 deletions apps/redi-talent-pool/src/components/templates/LoggedIn.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
import { Loader } from '@talent-connect/shared-atomic-design-components'
import { ReactNode } from 'react'
import { Columns, Container } from 'react-bulma-components'
import { useLocation } from 'react-router-dom'
import { useIsBusy } from '../../hooks/useIsBusy'
import { TpMainNavItem } from '../molecules/TpMainNavItem'
import { Navbar } from '../organisms'
Expand All @@ -25,6 +26,7 @@ const LoggedIn = ({ children, hideNavigation }: Props) => {
myTpData.data?.tpCurrentUserDataGet?.tpJobseekerDirectoryEntry

const isBusy = useIsBusy()
const location = useLocation()

// Determine user type (jobseeker, company representative, or undefined), then
// inform Hotjar about it (we're using its IDENTIFY API)
Expand Down
108 changes: 64 additions & 44 deletions apps/redi-talent-pool/src/pages/app/browse/BrowseCompany.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
Checkbox,
FilterDropdown,
Icon,
Pagination,
SearchField,
} from '@talent-connect/shared-atomic-design-components'
import { LANGUAGES } from '@talent-connect/shared-config'
Expand All @@ -23,6 +24,7 @@ import {
topSkillsIdToLabelMap,
} from '@talent-connect/talent-pool/config'
import { objectEntries } from '@talent-connect/typescript-utilities'
import { useState } from 'react'
import { Columns, Element, Tag } from 'react-bulma-components'
import { useQueryClient } from 'react-query'
import {
Expand All @@ -40,16 +42,13 @@ import {
useTpCompanyUnmarkJobseekerAsFavouriteMutation,
} from './BrowseCompany.generated'

const germanFederalStatesOptions = objectEntries(germanFederalStates).map(
([value, label]) => ({
value,
label,
})
)
const JOBSEEKER_CARDS_PER_PAGE = 12
const PAGINATION_SCROLL_POSITION = 350

export function BrowseCompany() {
const queryClient = useQueryClient()

const [currentPageNumber, setCurrentPageNumber] = useState(1)
const [query, setQuery] = useQueryParams({
name: withDefault(StringParam, ''),
desiredLanguages: withDefault(ArrayParam, []),
Expand Down Expand Up @@ -97,8 +96,6 @@ export function BrowseCompany() {
//joinsMunich24SummerJobFair,
},
})
const jobseekerProfiles =
jobseekerProfilesQuery.data?.tpJobseekerDirectoryEntriesVisible

const favoritedJobseekersQuery =
useTpCompanyFavouritedJobseekerProfilesQuery()
Expand All @@ -107,6 +104,33 @@ export function BrowseCompany() {
const unfavouriteJobseekerMutation =
useTpCompanyUnmarkJobseekerAsFavouriteMutation()

const jobseekerProfiles =
jobseekerProfilesQuery?.data?.tpJobseekerDirectoryEntriesVisible

const isJobseekerFavorite = (profileId) => {
return favoritedJobseekersQuery.data?.tpCompanyFavoritedJobseekerProfiles?.some(
(p) => p.favoritedTpJobseekerProfileId === profileId
)
}

// Filter the jobseekerProfiles based on the onlyFavorites flag before pagination
const filteredJobseekerProfiles = jobseekerProfiles?.filter((profile) => {
if (!onlyFavorites) return true
return isJobseekerFavorite(profile.id)
})

const lastItemIndex = currentPageNumber * JOBSEEKER_CARDS_PER_PAGE
const firstItemIndex = lastItemIndex - JOBSEEKER_CARDS_PER_PAGE
const currentItems = filteredJobseekerProfiles?.slice(
firstItemIndex,
lastItemIndex
)

const totalItems = filteredJobseekerProfiles?.length
const totalPagesNumber = totalItems
? Math.ceil(totalItems / JOBSEEKER_CARDS_PER_PAGE)
: undefined

const handleFavoriteJobseeker = async (tpJobseekerProfileId: string) => {
const isFavorite =
favoritedJobseekersQuery.data?.tpCompanyFavoritedJobseekerProfiles
Expand Down Expand Up @@ -194,15 +218,15 @@ export function BrowseCompany() {
style={{ flexGrow: 1 }}
>
Browse our Talent Pool
{jobseekerProfiles?.length ? ` (${jobseekerProfiles.length})` : ''}
{totalItems ? ` (${totalItems})` : ''}
</Element>
<Element
renderAs="p"
textSize={4}
responsive={{ mobile: { textSize: { value: 6 } } }}
className="oneandhalf-bs"
>
Browse our Jobseeker profiles and find the talent you're looking for.
Search our Jobseeker profiles to find the talent you're looking for.
</Element>
<div className="filters">
<div className="filters-inner">
Expand Down Expand Up @@ -373,41 +397,31 @@ export function BrowseCompany() {
)}
</div>
<Columns>
{jobseekerProfiles
?.filter((profile) => {
if (!onlyFavorites) return true
const isFavorite =
favoritedJobseekersQuery.data?.tpCompanyFavoritedJobseekerProfiles
?.map((p) => p.favoritedTpJobseekerProfileId)
?.includes(profile.id)
return isFavorite
})
.map((profile) => {
const isFavorite =
favoritedJobseekersQuery.data?.tpCompanyFavoritedJobseekerProfiles
?.map((p) => p.favoritedTpJobseekerProfileId)
?.includes(profile.id)

if (!isFavorite && onlyFavorites) return

return (
<Columns.Column
key={profile.id}
mobile={{ size: 12 }}
tablet={{ size: 6 }}
desktop={{ size: 4 }}
>
<JobseekerProfileCard
key={profile.id}
jobseekerProfile={profile}
linkTo={`/app/jobseeker-profile/${profile.id}`}
toggleFavorite={handleFavoriteJobseeker}
isFavorite={isFavorite}
/>
</Columns.Column>
)
})}
{currentItems?.map((profile) => (
<Columns.Column
key={profile.id}
mobile={{ size: 12 }}
tablet={{ size: 6 }}
desktop={{ size: 4 }}
>
<JobseekerProfileCard
key={profile.id}
jobseekerProfile={profile}
linkTo={`/app/jobseeker-profile/${profile.id}`}
toggleFavorite={handleFavoriteJobseeker}
isFavorite={isJobseekerFavorite(profile.id)}
/>
</Columns.Column>
))}
</Columns>
{totalItems > JOBSEEKER_CARDS_PER_PAGE && (
<Pagination
totalPagesNumber={totalPagesNumber}
currentPageNumber={currentPageNumber}
setCurrentPageNumber={setCurrentPageNumber}
scrollPosition={PAGINATION_SCROLL_POSITION}
/>
)}
</LoggedIn>
)
}
Expand All @@ -427,6 +441,12 @@ const desiredLanguagesOptions = Object.entries(LANGUAGES).map(
label,
})
)
const germanFederalStatesOptions = objectEntries(germanFederalStates).map(
([value, label]) => ({
value,
label,
})
)

interface FilterTagProps {
id: string
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ function FormDraggableAccordion({
</Columns.Column>
<Columns.Column onClick={() => setShowAnswer(!showAnswer)} narrow>
<Icon
icon="chevron"
icon="chevronDown"
size="small"
className={classnames({ 'icon--rotate': showAnswer })}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { formSelectStyles } from './FormSelect.styles'

export const DropdownIndicator = (props: any) => (
<components.DropdownIndicator {...props}>
<Icon icon="chevron" size="small" />
<Icon icon="chevronDown" size="small" />
</components.DropdownIndicator>
)

Expand Down
4 changes: 4 additions & 0 deletions libs/shared-atomic-design-components/src/lib/atoms/Icon.scss
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,8 @@
&--active {
cursor: pointer;
}

&--disabled path {
fill: $grey-light;
}
}
10 changes: 8 additions & 2 deletions libs/shared-atomic-design-components/src/lib/atoms/Icon.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,14 @@ import { ReactComponent as Career } from '../../assets/images/career.svg'
import { ReactComponent as Certificate } from '../../assets/images/certificate.svg'
import { ReactComponent as Chat } from '../../assets/images/chat.svg'
import { ReactComponent as Checkmark } from '../../assets/images/checkmark.svg'
import { ReactComponent as Chevron } from '../../assets/images/chevron.svg'
import { ReactComponent as ChevronDown } from '../../assets/images/chevron-down.svg'
import { ReactComponent as ChevronLeft } from '../../assets/images/chevron-left.svg'
import { ReactComponent as ChevronRight } from '../../assets/images/chevron-right.svg'
import { ReactComponent as Clipboard } from '../../assets/images/clipboard.svg'
import { ReactComponent as Delete } from '../../assets/images/delete.svg'
import { ReactComponent as EditLightGrey } from '../../assets/images/edit-lightgrey.svg'
import { ReactComponent as Edit } from '../../assets/images/edit.svg'
import { ReactComponent as EllipsisHorizontal } from '../../assets/images/ellipsis-horizontal.svg'
import { ReactComponent as Ellipsis } from '../../assets/images/ellipsis.svg'
import { ReactComponent as Fb } from '../../assets/images/fb.svg'
import { ReactComponent as Hamburger } from '../../assets/images/hamburger.svg'
Expand Down Expand Up @@ -49,11 +52,14 @@ const Icons = {
edit: Edit,
editLightGrey: EditLightGrey,
ellipsis: Ellipsis,
ellipsisHorizontal: EllipsisHorizontal,
delete: Delete,
refresh: Refresh,
link: Link,
cancel: Cancel,
chevron: Chevron,
chevronDown: ChevronDown,
chevronLeft: ChevronLeft,
chevronRight: ChevronRight,
heart: Heart,
heartFilled: HeartFilled,
clipboard: Clipboard,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ function FaqItem({ question, answer }: Props) {
</Columns.Column>
<Columns.Column narrow>
<Icon
icon="chevron"
icon="chevronDown"
size="small"
className={classnames({ 'icon--rotate': showAnswer })}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ const FilterDropdown = ({
>
Filter by {label}
<Icon
icon="chevron"
icon="chevronDown"
size="small"
className={classnames({
'icon--rotate': showDropdown,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@import '../styles/_variables.scss';

.icon-hover:hover path {
fill: $redi-orange-dark;
}
Loading

0 comments on commit d3dfac8

Please sign in to comment.