Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: VC filter #521

Merged
merged 7 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/chatty-plants-notice.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@blockchain-lab-um/dapp': minor
---

Add better popover for filtering VCs on dashboard
4 changes: 2 additions & 2 deletions packages/dapp/src/components/Controlbar/Controlbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@ import clsx from 'clsx';
import { useTranslations } from 'next-intl';

import ImportModal from '@/components/ImportModal';
import DataStoreCombobox from '@/components/VCTable/DataStoreCombobox';
import GlobalFilter from '@/components/VCTable/GlobalFilter';
import ViewTabs from '@/components/VCTable/ViewTabs';
import { stringifyCredentialSubject } from '@/utils/format';
import { useGeneralStore, useMascaStore, useToastStore } from '@/stores';
import FilterPopover from '../VCTable/FilterPopover';

// import PlaygroundModal from '../PlaygroundModal';

Expand Down Expand Up @@ -162,7 +162,7 @@ const Controlbar = () => {
<div className="mb-4 grid grid-cols-11 grid-rows-2 gap-y-4 md:grid-rows-1">
{vcs.length > 0 && (
<div className="col-span-11 col-start-1 row-start-2 flex gap-x-2 md:col-span-5 md:row-start-1">
<DataStoreCombobox isConnected={isConnected} vcs={vcs} />
<FilterPopover vcs={vcs} />
<GlobalFilter isConnected={isConnected} vcs={vcs} />
</div>
)}
Expand Down
25 changes: 25 additions & 0 deletions packages/dapp/src/components/VCTable/FilterPopover/CheckBox.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';

interface CheckBoxProps {
selected: boolean;
setSelected: (selected: boolean) => void;
children: React.ReactNode;
}

export const CheckBox = ({
selected,
setSelected,
children,
}: CheckBoxProps) => (
<div className="dark:text-navy-blue-200 flex items-center font-medium text-gray-700">
<input
className="dark:accent-orange-accent-dark h-4 w-4 accent-pink-500"
type="checkbox"
checked={selected}
onChange={() => {
setSelected(!selected);
}}
/>
<span className="ml-2 max-w-[190px] truncate">{children}</span>
</div>
);
111 changes: 111 additions & 0 deletions packages/dapp/src/components/VCTable/FilterPopover/CredentialTypes.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
import React, { useState } from 'react';
import { ChevronRightIcon } from '@heroicons/react/24/solid';
import clsx from 'clsx';
import { useTranslations } from 'next-intl';

import { useTableStore } from '@/stores';
import { CheckBox } from './CheckBox';

export const CredentialTypes = () => {
const t = useTranslations('FilterPopover');

const [open, setOpen] = useState(false);
const { credentialTypes, setCredentialTypes } = useTableStore((state) => ({
credentialTypes: state.credentialTypes,
setCredentialTypes: state.setCredentialTypes,
}));
const [filter, setFilter] = useState('');

return (
<div>
<div className="flex items-center justify-between pr-2">
<button
onClick={() => {
setOpen(!open);
}}
>
<div className="dark:text-navy-blue-100 my-1 ml-2 flex items-center gap-x-2 text-gray-700">
<ChevronRightIcon
className={clsx(
'animated-transition h-5 w-5 ',
`${open ? 'rotate-90' : ''}`
)}
/>
{t('type')}
</div>
</button>
{open &&
(credentialTypes.filter((type) => type.selected).length > 0 ? (
<button
className="text-sm text-red-500 hover:text-red-700 dark:text-red-300 hover:dark:text-red-500"
onClick={() => {
setCredentialTypes(
credentialTypes.map((type) => ({
...type,
selected: false,
}))
);
}}
>
clear ({credentialTypes.filter((type) => type.selected).length})
</button>
) : (
<button
className="text-sm text-red-500 hover:text-red-700 dark:text-red-300 hover:dark:text-red-500"
onClick={() => {
setCredentialTypes(
credentialTypes.map((type) => ({
...type,
selected: true,
}))
);
}}
>
select all
</button>
))}
</div>
{open && (
<div className="dark:bg-navy-blue-500/40 bg-[#FFF8F9] p-2">
<input
className="dark:bg-navy-blue-700 dark:text-navy-blue-50 dark:border-navy-blue-400 w-full rounded-md border border-gray-300 bg-white px-2 py-1 focus:outline-none"
placeholder="Search Types..."
onChange={(e) => {
setFilter(e.target.value);
}}
value={filter}
/>
<div className="scrollbar-thumb-rounded scrollbar-thumb-pink-500 dark:scrollbar-thumb-orange-accent-dark scrollbar-thin mt-2 max-h-[160px] overflow-scroll overflow-x-hidden">
{credentialTypes.map((type) => {
if (!type.type.toLowerCase().includes(filter.toLowerCase())) {
return null;
}

return (
<div key={type.type} className="my-2">
<CheckBox
selected={type.selected}
setSelected={(selected) => {
const newCredentialTypes = credentialTypes.map((tp) => {
if (tp.type === type.type) {
return {
...type,
selected,
};
}
return tp;
});
setCredentialTypes(newCredentialTypes);
}}
>
{type.type}
</CheckBox>
</div>
);
})}
</div>
</div>
)}
</div>
);
};
65 changes: 65 additions & 0 deletions packages/dapp/src/components/VCTable/FilterPopover/DataStores.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import React, { useState } from 'react';
import { ChevronRightIcon } from '@heroicons/react/24/solid';
import clsx from 'clsx';
import { useTranslations } from 'next-intl';

import { useTableStore } from '@/stores';
import { CheckBox } from './CheckBox';

const DataStoreNames = {
snap: 'Snap',
ceramic: 'Ceramic',
};

export const DataStores = () => {
const t = useTranslations('FilterPopover');
const [open, setOpen] = useState(false);
const { dataStores, setDataStores } = useTableStore((state) => ({
dataStores: state.dataStores,
setDataStores: state.setDataStores,
}));

return (
<div>
<button
onClick={() => {
setOpen(!open);
}}
>
<div className="dark:text-navy-blue-100 my-1 ml-2 mt-4 flex items-center gap-x-2 text-gray-700">
<ChevronRightIcon
className={clsx(
'animated-transition h-5 w-5',
`${open ? 'rotate-90' : ''}`
)}
/>
{t('datastore')}
</div>
</button>
{open && (
<div className="dark:bg-navy-blue-500/40 bg-[#FFF8F9] p-2">
{dataStores.map((dataStore) => (
<CheckBox
key={dataStore.dataStore}
selected={dataStore.selected}
setSelected={(selected) => {
const newDataStores = dataStores.map((ds) => {
if (ds.dataStore === dataStore.dataStore) {
return {
...dataStore,
selected,
};
}
return ds;
});
setDataStores(newDataStores);
}}
>
{DataStoreNames[dataStore.dataStore]}
</CheckBox>
))}
</div>
)}
</div>
);
};
66 changes: 66 additions & 0 deletions packages/dapp/src/components/VCTable/FilterPopover/Ecosystems.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import React, { useState } from 'react';
import { ChevronRightIcon } from '@heroicons/react/24/solid';
import clsx from 'clsx';
import { useTranslations } from 'next-intl';

import { useTableStore } from '@/stores';
import { CheckBox } from './CheckBox';

const EcosystemSNames = {
ebsi: 'EBSI',
polygonid: 'Polygon',
other: 'Other',
};

export const Ecosystems = () => {
const t = useTranslations('FilterPopover');
const [open, setOpen] = useState(false);
const { ecosystems, setEcosystems } = useTableStore((state) => ({
ecosystems: state.ecosystems,
setEcosystems: state.setEcosystems,
}));

return (
<div>
<button
onClick={() => {
setOpen(!open);
}}
>
<div className="dark:text-navy-blue-100 my-1 ml-2 flex items-center gap-x-2 text-gray-700">
<ChevronRightIcon
className={clsx(
'animated-transition h-5 w-5',
`${open ? 'rotate-90' : ''}`
)}
/>
{t('ecosystem')}
</div>
</button>
{open && (
<div className="dark:bg-navy-blue-500/40 bg-[#FFF8F9] p-2">
{ecosystems.map((ecosystem) => (
<CheckBox
key={ecosystem.ecosystem}
selected={ecosystem.selected}
setSelected={(selected) => {
const newDataStores = ecosystems.map((ds) => {
if (ds.ecosystem === ecosystem.ecosystem) {
return {
...ecosystem,
selected,
};
}
return ds;
});
setEcosystems(newDataStores);
}}
>
{EcosystemSNames[ecosystem.ecosystem]}
</CheckBox>
))}
</div>
)}
</div>
);
};
Loading