Skip to content

Commit

Permalink
Add sidebar for startup partners
Browse files Browse the repository at this point in the history
[CORE-609]
  • Loading branch information
RoyEJohnson committed Dec 9, 2024
1 parent 8096a29 commit 5279a10
Show file tree
Hide file tree
Showing 3 changed files with 142 additions and 38 deletions.
31 changes: 31 additions & 0 deletions src/app/pages/partners/results/results.scss
Original file line number Diff line number Diff line change
Expand Up @@ -104,4 +104,35 @@
}
}
}

.with-sidebar {
display: flex;
flex-direction: row;
gap: 3rem;
max-width: 120rem;
margin: 0 auto;

> .boxed {
grid-gap: 3rem;
}

.grid {
max-width: unset;
}

> .sidebar {
min-width: 20rem;
border: thin solid black;
height: max-content;

h2 {
background-color: white;
text-align: center;
}

.grid {
gap: 0.2rem;
}
}
}
}
123 changes: 90 additions & 33 deletions src/app/pages/partners/results/results.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,9 @@ import {useDataFromPromise} from '~/helpers/page-data-utils';
import SelectedPartnerDialog from './selected-partner-dialog';
import shuffle from 'lodash/shuffle';
import orderBy from 'lodash/orderBy';
import './results.scss';
import partition from 'lodash/partition';
import {differenceInYears} from 'date-fns';
import './results.scss';

export const costOptions = ['$0 - $10', '$11 - $25', '$26 - $40', '> $40'].map(
(label) => ({
Expand Down Expand Up @@ -112,10 +113,7 @@ function filterBy(
// eslint-disable-next-line complexity
function useFilteredEntries(entries: PartnerEntry[]) {
const {books, types, advanced, sort, resultCount} = useSearchContext();
const unfilteredResults = React.useMemo(
() => shuffle(entries),
[entries]
);
const unfilteredResults = React.useMemo(() => shuffle(entries), [entries]);
const finalResult = React.useMemo(() => {
let result = filterByBooks(unfilteredResults, books);

Expand Down Expand Up @@ -160,8 +158,8 @@ function useFilteredEntries(entries: PartnerEntry[]) {
}

function advancedFilterKeys(partnerEntry: PartnerData) {
return (Object.keys(partnerEntry) as Array<keyof PartnerData>).filter(
(k) => ([false, true] as unknown[]).includes(partnerEntry[k])
return (Object.keys(partnerEntry) as Array<keyof PartnerData>).filter((k) =>
([false, true] as unknown[]).includes(partnerEntry[k])
);
}

Expand Down Expand Up @@ -204,11 +202,49 @@ function resultEntry(pd: PartnerData) {
ratingCount: pd.rating_count,
partnershipLevel: pd.partnership_level,
yearsAsPartner: pd.partner_anniversary_date
? differenceInYears(Date.now(), new Date(pd.partner_anniversary_date))
? differenceInYears(
Date.now(),
new Date(pd.partner_anniversary_date)
)
: null
};
}

function Sidebar({entries}: {entries: PartnerEntry[]}) {
return (
<div className="sidebar">
<div className="sidebar-content">
<h2>Startups</h2>
<ResultGrid entries={entries} />
</div>
</div>
);
}

const headings: Record<Ages, string> = {
'10': '10+ years as Technology Partners',
'7': '7-10 years as partners',
'4': '4-7 years as partners',
'1': '1-3 years as partners',
new: 'New partners'
};
const ages: Ages[] = ['10', '7', '4', '1', 'new'];

function HeadingAndResultGrid({
age,
entries
}: {
age: Ages;
entries: PartnerEntry[];
}) {
return (
<React.Fragment>
<h2>{headings[age as Ages]}</h2>
<ResultGrid entries={entries} />
</React.Fragment>
);
}

type Ages = '10' | '7' | '4' | '1' | 'new';

function ResultGridLoader({
Expand All @@ -223,15 +259,11 @@ function ResultGridLoader({
[partnerData]
);
const filteredEntries = useFilteredEntries(entries);
const ages: Ages[] = ['10', '7', '4', '1'];
const headings: Record<Ages, string> = {
'10': '10+ years as Technology Partners',
'7': '7-10 years as partners',
'4': '4-7 years as partners',
'1': '1-3 years as partners',
new: 'New partners'
};
const partnersByAge = filteredEntries.reduce((a, b) => {
const [startups, nonStartups] = partition(
filteredEntries,
(e) => e.partnershipLevel?.toLowerCase() === 'startup'
);
const partnersByAge = nonStartups.reduce((a, b) => {
const bucket =
ages.find((age) => (b.yearsAsPartner ?? 0) >= Number(age)) ?? 'new';

Expand All @@ -241,22 +273,52 @@ function ResultGridLoader({
a[bucket].push(b);
return a;
}, {} as Record<string, PartnerEntry[]>);
const foundAges = ages.filter((a) => partnersByAge[a]);

if (startups.length > 0) {
const [firstAge, ...otherAges] = foundAges;

return (
<section className="results">
<div className="boxed">
<HeadingAndResultGrid
age={firstAge}
entries={partnersByAge[firstAge]}
/>
</div>
<SelectedPartnerDialog
linkTexts={linkTexts}
entries={filteredEntries}
/>
<div className="with-sidebar">
<div className="boxed">
{otherAges.map((age) => (
<HeadingAndResultGrid
key={age}
age={age}
entries={partnersByAge[age]}
/>
))}
</div>
<Sidebar entries={startups} />
</div>
</section>
);
}
return (
<React.Fragment>
{([...ages, 'new'] as Ages[])
.filter((age) => age in partnersByAge)
.map((age) => (
<React.Fragment key={age}>
<h2>{headings[age as Ages]}</h2>
<ResultGrid entries={partnersByAge[age]} />
</React.Fragment>
))}
<section className="results boxed">
{foundAges.map((age) => (
<HeadingAndResultGrid
key={age}
age={age}
entries={partnersByAge[age]}
/>
))}
<SelectedPartnerDialog
linkTexts={linkTexts}
entries={filteredEntries}
/>
</React.Fragment>
</section>
);
}

Expand All @@ -269,14 +331,9 @@ export default function Results({linkTexts}: {linkTexts: LinkTexts}) {
[partnerData]
);


if (!partnerData) {
return null;
}

return (
<section className="results boxed">
<ResultGridLoader {...{partnerData: visiblePartners, linkTexts}} />
</section>
);
return <ResultGridLoader {...{partnerData: visiblePartners, linkTexts}} />;
}
26 changes: 21 additions & 5 deletions test/src/pages/partners/partners.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ describe('partners/results', () => {
});
});

describe('full page', () => {
describe('partners full page', () => {
const user = userEvent.setup();

function Component() {
Expand All @@ -74,12 +74,11 @@ describe('full page', () => {
</ShellContextProvider>
);
}
beforeEach(() => {
mockSfPartners.mockResolvedValue(sfPartners);
render(<Component />);
});

jest.setTimeout(12000);
it('displays grid that filters by type', async () => {
mockSfPartners.mockResolvedValue(sfPartners);
render(<Component />);
const buttons = await screen.findAllByRole('button');

expect(buttons).toHaveLength(6);
Expand All @@ -93,6 +92,8 @@ describe('full page', () => {
expect(screen.getAllByRole('link')).toHaveLength(4);
});
it('filters by book', async () => {
mockSfPartners.mockResolvedValue(sfPartners);
render(<Component />);
const bookButton = await screen.findByRole('button', {name: 'Books'});

await user.click(bookButton);
Expand All @@ -106,6 +107,8 @@ describe('full page', () => {
expect(checkboxes).toHaveLength(24);
});
it('filters by advanced filter', async () => {
mockSfPartners.mockResolvedValue(sfPartners);
render(<Component />);
const filterButton = await screen.findByRole('button', {
name: 'Advanced Filters'
});
Expand All @@ -122,6 +125,8 @@ describe('full page', () => {
expect(screen.getAllByRole('link')).toHaveLength(5);
});
it('sorts', async () => {
mockSfPartners.mockResolvedValue(sfPartners);
render(<Component />);
const sortButtons = await screen.findAllByRole('button', {
name: 'Sort'
});
Expand Down Expand Up @@ -170,11 +175,22 @@ describe('full page', () => {
]);
});
it('shows details in dialog', async () => {
mockSfPartners.mockResolvedValue(sfPartners);
render(<Component />);
const partnerLink = await screen.findByRole('link', {name: 'Rice Online Learning'});

await user.click(partnerLink);
screen.getByRole('dialog');
screen.getByText('through the edX platform', {exact: false});
await user.click(screen.getByRole('button', {name: 'close'}));
});
it('displays sidebar of startups', async () => {
sfPartners[0].partnership_level = 'startup'; // eslint-disable-line
mockSfPartners.mockResolvedValue(sfPartners);
render(<Component />);
const startupHeading = await screen.findByRole('heading', {level: 2, name: 'Startups'});

expect(startupHeading.parentNode?.textContent).toContain(sfPartners[0].partner_name);
sfPartners[0].partnership_level = 'Full partner'; // eslint-disable-line
});
});

0 comments on commit 5279a10

Please sign in to comment.