Skip to content

Commit 7f95cc8

Browse files
committed
Update Collective profile prototype
1 parent a47ae3d commit 7f95cc8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

54 files changed

+877
-2159
lines changed

components/crowdfunding-redesign/Accounts.tsx

-448
This file was deleted.

components/crowdfunding-redesign/AccountsList.tsx

+1-29
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,8 @@
11
import React from 'react';
2-
import type { Column, ColumnDef, Row, TableMeta } from '@tanstack/react-table';
3-
import clsx from 'clsx';
4-
import { isNil, omit } from 'lodash';
5-
import { ArrowDown10, ArrowDownZA, ArrowUp10, ArrowUpZA } from 'lucide-react';
6-
import { FormattedMessage } from 'react-intl';
72

8-
import type {
9-
AccountMetricsFragment,
10-
Currency,
11-
OverviewMetricsQueryVariables,
12-
} from '../../lib/graphql/types/v2/graphql';
13-
import type { useQueryFilterReturnType } from '../../lib/hooks/useQueryFilter';
14-
import { getCollectivePageRoute } from '../../lib/url-helpers';
15-
16-
import { AccountHoverCard } from '../AccountHoverCard';
17-
import Avatar from '../Avatar';
18-
import type { schema } from '../dashboard/sections/overview/CollectiveOverview';
19-
import type { MetricProps } from '../dashboard/sections/overview/Metric';
20-
import { ChangeBadge, getPercentageDifference } from '../dashboard/sections/overview/Metric';
21-
import FormattedMoneyAmount from '../FormattedMoneyAmount';
22-
import Link from '../Link';
23-
import { DataTable } from '../table/DataTable';
24-
import { Badge } from '../ui/Badge';
25-
import { Button } from '../ui/Button';
26-
import { Checkbox } from '../ui/Checkbox';
273
import { AccountsSublist } from './AccountsSublist';
284

29-
export default function AccountsList({ data, queryFilter, loading, metric }) {
5+
export default function AccountsList({ data, queryFilter, metric }) {
306
const currency = data?.account?.[metric.id]?.current?.currency;
317

328
const meta = {
@@ -36,10 +12,6 @@ export default function AccountsList({ data, queryFilter, loading, metric }) {
3612
metric,
3713
};
3814

39-
// if (error) {
40-
// return <MessageBoxGraphqlError error={error} />;
41-
// }
42-
4315
return (
4416
<div className="space-y-8">
4517
<AccountsSublist label="Main account" type="COLLECTIVE" data={data} metric={metric} meta={meta} />
Original file line numberDiff line numberDiff line change
@@ -1,165 +1,23 @@
11
import React from 'react';
2-
import type { Column, ColumnDef, Row, TableMeta } from '@tanstack/react-table';
3-
import clsx from 'clsx';
42
import { isNil, omit } from 'lodash';
5-
import { ArrowDown10, ArrowDownZA, ArrowUp10, ArrowUpZA, ChevronRight } from 'lucide-react';
6-
import { FormattedMessage } from 'react-intl';
3+
import { ArrowUp10, ChevronRight } from 'lucide-react';
4+
import { useRouter } from 'next/router';
75

8-
import type {
9-
AccountMetricsFragment,
10-
Currency,
11-
OverviewMetricsQueryVariables,
12-
} from '../../lib/graphql/types/v2/graphql';
13-
import type { useQueryFilterReturnType } from '../../lib/hooks/useQueryFilter';
14-
import { getCollectivePageRoute } from '../../lib/url-helpers';
6+
import type { AccountMetricsFragment } from '../../lib/graphql/types/v2/graphql';
157

16-
import { AccountHoverCard } from '../AccountHoverCard';
17-
import Avatar from '../Avatar';
18-
import type { schema } from '../dashboard/sections/overview/CollectiveOverview';
19-
import type { MetricProps } from '../dashboard/sections/overview/Metric';
20-
import { ChangeBadge, getPercentageDifference } from '../dashboard/sections/overview/Metric';
8+
import { getPercentageDifference } from '../dashboard/sections/overview/Metric';
219
import FormattedMoneyAmount from '../FormattedMoneyAmount';
2210
import Link from '../Link';
23-
import { DataTable } from '../table/DataTable';
24-
import { Badge } from '../ui/Badge';
2511
import { Button } from '../ui/Button';
26-
import { Checkbox } from '../ui/Checkbox';
27-
import { useRouter } from 'next/router';
12+
13+
import { triggerPrototypeToast } from './helpers';
14+
2815
type AccountMetricsRow = AccountMetricsFragment & {
2916
current: number;
3017
comparison?: number;
3118
percentageDifference?: number;
3219
};
3320

34-
interface AccountMetricsMeta extends TableMeta<AccountMetricsRow> {
35-
currency: Currency;
36-
isAmount: boolean;
37-
queryFilter: useQueryFilterReturnType<typeof schema, OverviewMetricsQueryVariables>;
38-
metric: MetricProps;
39-
}
40-
41-
const SortableHeader = ({
42-
column,
43-
label,
44-
type,
45-
align,
46-
}: {
47-
column: Column<AccountMetricsRow, unknown>;
48-
label: React.ReactNode;
49-
type?: 'alphabetic' | 'numerical';
50-
align?: 'left' | 'right';
51-
}) => {
52-
const isSorted = column.getIsSorted();
53-
const isSortedDesc = isSorted === 'desc';
54-
const UpIcon = type === 'alphabetic' ? ArrowUpZA : ArrowUp10;
55-
const DownIcon = type === 'alphabetic' ? ArrowDownZA : ArrowDown10;
56-
const SortIcon = isSortedDesc || !isSorted ? UpIcon : DownIcon;
57-
return (
58-
<div className={clsx('flex items-center', align === 'right' && 'justify-end')}>
59-
<Button
60-
variant="ghost"
61-
size="xs"
62-
className={clsx('group/btn -m-2 gap-2', isSorted && 'text-foreground')}
63-
onClick={() => column.toggleSorting(!isSortedDesc)}
64-
>
65-
<SortIcon
66-
className={clsx(
67-
'h-4 w-4 transition-colors',
68-
isSorted ? 'text-muted-foreground' : 'text-transparent group-hover/btn:text-muted-foreground',
69-
)}
70-
/>
71-
<span className={clsx(align === 'left' && '-order-1')}>{label}</span>
72-
</Button>
73-
</div>
74-
);
75-
};
76-
const columns: ColumnDef<AccountMetricsRow>[] = [
77-
{
78-
id: 'name',
79-
accessorKey: 'name',
80-
header: ({ column }) => (
81-
<SortableHeader
82-
column={column}
83-
type="alphabetic"
84-
label={<FormattedMessage defaultMessage="Name" id="HAlOn1" />}
85-
align="left"
86-
/>
87-
),
88-
meta: { className: 'min-w-0 max-w-[300px]' },
89-
90-
cell: ({ row, table }) => {
91-
const account = row.original;
92-
// const { queryFilter } = table.options.meta as AccountMetricsMeta;
93-
// const selectedAccountSlug = queryFilter.values.account;
94-
return (
95-
<div className="flex items-center gap-3 text-base">
96-
<div className="flex items-center gap-1.5 overflow-hidden">
97-
<AccountHoverCard
98-
account={account}
99-
trigger={
100-
<div className="max-w-[400px] truncate">
101-
<Link
102-
href={getCollectivePageRoute(account)}
103-
className={clsx('truncate hover:underline group-hover/row:text-foreground')}
104-
>
105-
{account.name}
106-
</Link>
107-
</div>
108-
}
109-
/>
110-
111-
{account.isArchived && (
112-
<Badge size="xs" className="capitalize">
113-
Archived {account.type.toLowerCase()}
114-
</Badge>
115-
)}
116-
</div>
117-
</div>
118-
);
119-
},
120-
},
121-
{
122-
id: 'current',
123-
accessorKey: 'current',
124-
meta: { className: 'text-right' },
125-
header: ({ column, table }) => {
126-
const meta = table.options.meta as AccountMetricsMeta;
127-
return <SortableHeader align="right" column={column} label={meta.metric.label} />;
128-
},
129-
sortingFn: (rowA: Row<AccountMetricsRow>, rowB: Row<AccountMetricsRow>): number => {
130-
const a = rowA.original.current;
131-
const b = rowB.original.current;
132-
133-
const diff = a - b;
134-
135-
// sort by comparison value if current is the same
136-
if (diff === 0) {
137-
const rowAPrevious = rowA.original.comparison;
138-
const rowBPrevious = rowB.original.comparison;
139-
return rowAPrevious - rowBPrevious;
140-
}
141-
return a - b;
142-
},
143-
cell: ({ cell, table }) => {
144-
const current = cell.getValue() as number;
145-
const meta = table.options.meta as AccountMetricsMeta;
146-
147-
return (
148-
<div className="flex items-center justify-end gap-2">
149-
<span className="text-base font-medium">
150-
{meta.isAmount ? (
151-
<FormattedMoneyAmount amount={current} currency={meta.currency} precision={2} showCurrencyCode={false} />
152-
) : (
153-
current.toLocaleString()
154-
)}
155-
</span>
156-
<ChevronRight size={20} className="text-muted-foreground" />
157-
</div>
158-
);
159-
},
160-
},
161-
];
162-
16321
export function AccountsSublist({ label, type, data, metric, meta }) {
16422
const router = useRouter();
16523
const columnData: AccountMetricsRow[] = React.useMemo(() => {
@@ -178,10 +36,23 @@ export function AccountsSublist({ label, type, data, metric, meta }) {
17836
percentageDifference: getPercentageDifference(current, comparison),
17937
};
18038
});
181-
}, [metric.id, data]);
39+
}, [metric.id, data, type]);
40+
18241
return (
18342
<div className="">
184-
<h2 className="mb-3 px-2 text-lg font-semibold text-slate-800">{label}</h2>
43+
<div className="mb-2 flex items-center justify-between gap-4 px-2">
44+
<h2 className="text-lg font-semibold text-slate-800">{label}</h2>
45+
<Button
46+
variant="ghost"
47+
size="sm"
48+
className={'group/btn -m-2 gap-2 text-foreground'}
49+
onClick={triggerPrototypeToast}
50+
disabled={columnData.length === 1}
51+
>
52+
<span>{metric.id === 'balance' ? 'Balance' : metric.label}</span>
53+
<ArrowUp10 className="h-4 w-4 text-muted-foreground transition-colors" />
54+
</Button>
55+
</div>
18556
<div className="flex flex-col divide-y overflow-hidden rounded-xl border bg-background">
18657
{columnData
18758
.sort((a, b) => b.current - a.current)
@@ -206,17 +77,6 @@ export function AccountsSublist({ label, type, data, metric, meta }) {
20677
</Link>
20778
))}
20879
</div>
209-
210-
{/* <DataTable
211-
hideHeader
212-
className="bg-background"
213-
columns={columns}
214-
data={columnData}
215-
initialSort={[{ id: 'current', desc: true }]}
216-
nbPlaceholders={nbPlaceholders}
217-
loading={loading}
218-
meta={meta}
219-
/> */}
22080
</div>
22181
);
22282
}

components/crowdfunding-redesign/Breadcrumb.tsx

+1-30
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,7 @@
1-
import { useRouter } from 'next/router';
21
import React from 'react';
3-
import Link from '../Link';
42
import { Slash } from 'lucide-react';
53

6-
const getPathdata = (router, collective, account) => {
7-
switch (router.pathname) {
8-
case '/preview/[collectiveSlug]/finances/[accountSlug]':
9-
return [{ href: `/preview/${router.query.collectiveSlug}/finances`, label: 'Finances' }];
10-
case '/preview/[collectiveSlug]/transactions/[groupId]':
11-
return [
12-
{ href: `/preview/${router.query.collectiveSlug}/finances`, label: 'Finances' },
13-
{
14-
href: `/preview/${router.query.collectiveSlug}/finances/${router.query.collectiveSlug}`,
15-
label: collective?.name,
16-
},
17-
];
18-
case '/preview/[collectiveSlug]/[accountSlug]/transactions/[groupId]':
19-
return [
20-
{ href: `/preview/${router.query.collectiveSlug}/finances`, label: 'Finances' },
21-
{
22-
href: `/preview/${router.query.collectiveSlug}/finances/${router.query.accountSlug}`,
23-
label: account?.name,
24-
},
25-
];
26-
case '/preview/[collectiveSlug]/projects/[accountSlug]':
27-
return [{ href: `/preview/${router.query.collectiveSlug}/projects`, label: 'Projects' }];
28-
case '/preview/[collectiveSlug]/events/[accountSlug]':
29-
return [{ href: `/preview/${router.query.collectiveSlug}/events`, label: 'Events' }];
30-
default:
31-
return [{ href: '', label: '' }];
32-
}
33-
};
4+
import Link from '../Link';
345

356
export function Breadcrumb({ breadcrumbs }) {
367
return (

components/crowdfunding-redesign/CollectiveHeader.tsx

-40
This file was deleted.

components/crowdfunding-redesign/ContentOverview.tsx

+24-6
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import React, { useEffect, useState } from 'react';
22
import { cva } from 'class-variance-authority';
3+
import { Interweave } from 'interweave';
34
// eslint-disable-next-line no-restricted-imports
45
import Link from 'next/link';
6+
import sanitizeHtml from 'sanitize-html';
7+
58
import { triggerPrototypeToast } from './helpers';
69

710
export const ContentOverview = ({ content }) => {
@@ -18,7 +21,7 @@ export const ContentOverview = ({ content }) => {
1821
const linkClasses = cva('px-2 font-semibold block hover:text-primary text-sm border-l-[3px]', {
1922
variants: {
2023
active: {
21-
true: 'border-primary/70',
24+
true: 'border-primary/80',
2225
false: 'border-transparent',
2326
},
2427
},
@@ -29,11 +32,26 @@ export const ContentOverview = ({ content }) => {
2932

3033
return (
3134
<div className="space-y-4">
32-
{headings.map(heading => (
33-
<Link href="#" key={heading} className={linkClasses()} onClick={triggerPrototypeToast}>
34-
{heading}
35-
</Link>
36-
))}
35+
<Link href="#" className={linkClasses({ active: true })} onClick={triggerPrototypeToast}>
36+
About
37+
</Link>
38+
{headings.map(heading => {
39+
const sanitizedKey = sanitizeHtml(heading, {
40+
allowedTags: [], // No tags allowed
41+
allowedAttributes: {}, // No attributes allowed
42+
}).replace(/[^a-zA-Z0-9-_]/g, '_'); // Replace unsafe characters
43+
44+
return (
45+
<Link
46+
href="#"
47+
key={sanitizedKey} // Use sanitized and unique key
48+
className={linkClasses()}
49+
onClick={triggerPrototypeToast}
50+
>
51+
<Interweave content={heading} />
52+
</Link>
53+
);
54+
})}
3755
</div>
3856
);
3957
};

0 commit comments

Comments
 (0)