Skip to content

Commit

Permalink
feat: Refetch Button & tooltip & Last time updated info
Browse files Browse the repository at this point in the history
  • Loading branch information
muntean.gm committed Mar 22, 2024
1 parent e2dd118 commit 701fec5
Show file tree
Hide file tree
Showing 12 changed files with 260 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { StatusOptions } from '@utils/api/credentials/credentials.type';
import { getStatusFilter } from '@utils/api/credentials/credentials.utils';
import { routes } from '@utils/routes';

import UpdateData from '@ui/UpdateData';
import PaginatedTable from '@ui/table/PaginatedTable';
import FilterMultiSelect from '@ui/table/filters/FilterMultiSelect';
import useClientSideMultiSelectFilter from '@ui/table/hooks/useClientSideMultiSelectFilter';
Expand Down Expand Up @@ -51,12 +52,13 @@ const OverallContent = () => {
<div className='mb-6 text-lg font-bold text-sky-950'>
{t('credentials.overall_requests')}
</div>
<div className='my-6'>
<div className='my-6 flex justify-between'>
<FilterMultiSelect
title={t('global.filter_by')}
{...statusFilterConfig}
disabled={false}
/>
<UpdateData onRefetch={onRefetch} />
</div>
<PaginatedTable
isLoading={isLoading}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { useGetVC } from '@utils/api/credentials/credentials.hook';
import { getStatusFilter } from '@utils/api/credentials/credentials.utils';
import { routes } from '@utils/routes';

import UpdateData from '@ui/UpdateData';
import PaginatedTable from '@ui/table/PaginatedTable';
import useServerSideTableData from '@ui/table/hooks/useServerSideTableData';

Expand All @@ -34,9 +35,13 @@ const PendingContent = () => {

return (
<div>
<div className='mb-6 text-lg font-bold text-sky-950'>
{t('credentials.latest_requests')}
<div className='mb-6 flex justify-between'>
<div className='text-lg font-bold text-sky-950'>
{t('credentials.latest_requests')}
</div>
<UpdateData onRefetch={onRefetch} />
</div>

<PaginatedTable
isLoading={isLoading}
columns={vcColumns}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,11 @@ export const useVCCommonColumns = (onRefetch: () => void) => {
</div>
);
},
enableSorting: false
enableSorting: false,
meta: {
pinned: 'right',
preventUnpinning: true
}
})
];
};
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { getStatusFilter } from '@utils/api/credentials/credentials.utils';
import { routes } from '@utils/routes';

import InfoCard from '@ui/InfoCard';
import UpdateData from '@ui/UpdateData';
import PaginatedTable from '@ui/table/PaginatedTable';
import FilterMultiSelect from '@ui/table/filters/FilterMultiSelect';
import useClientSideMultiSelectFilter from '@ui/table/hooks/useClientSideMultiSelectFilter';
Expand Down Expand Up @@ -85,12 +86,14 @@ const DashboardContent = () => {
<div className='mb-4 mt-6 text-lg font-bold text-sky-950'>
{t('credentials.latest_credentials')}
</div>
<div className='mb-6'>

<div className='mb-6 flex justify-between'>
<FilterMultiSelect
title={t('global.filter_by')}
{...statusFilterConfig}
disabled={false}
/>
<UpdateData onRefetch={onRefetch} />
</div>
<PaginatedTable
isLoading={isLoading}
Expand Down
69 changes: 69 additions & 0 deletions apps/frontend/components/ui/UpdateData.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
'use client';

import {
ArrowPathIcon,
InformationCircleIcon
} from '@heroicons/react/24/outline';
import { useTranslations } from 'next-intl';
import { useState } from 'react';

import { cn } from '@utils/cn';
import useTimeElapsed from '@utils/hooks/useTimeElapsed';

import Tooltip from '@ui/tooltip/Tooltip';

type TUpdateData = {
onRefetch: () => void;
};

const UpdateData = ({ onRefetch }: TUpdateData) => {
const [isAnimating, setIsAnimating] = useState(false);
const [startTime, setStartTime] = useState(Date.now());

const timeElapsed = useTimeElapsed(new Date(startTime));

const t = useTranslations();

const animate = () => {
setIsAnimating(true);
setTimeout(() => {
setIsAnimating(false);
}, 1000);
};

const handleRefetch = () => {
onRefetch();
setStartTime(Date.now());

animate();
};

return (
<div className='flex items-center gap-4'>
<div className='flex gap-2 text-sm text-slate-400'>
{timeElapsed && (
<>
<span>{t('global.updated_time_ago', { time: timeElapsed })}</span>
<Tooltip content={<div>{t('global.updated_tooltip')}</div>}>
<InformationCircleIcon className='h-4 w-4' />
</Tooltip>
</>
)}
</div>
<button
type='button'
className='flex cursor-pointer items-center gap-2 text-sm font-medium text-sky-950'
onClick={handleRefetch}
>
<span>{t('global.update_data')}</span>
<ArrowPathIcon
className={cn('h-4 w-4', {
'animate-spin-infinite': isAnimating
})}
/>
</button>
</div>
);
};

export default UpdateData;
49 changes: 49 additions & 0 deletions apps/frontend/components/ui/tooltip/Tooltip.components.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
import type { ComponentPropsWithoutRef, ElementRef } from 'react';
import { forwardRef } from 'react';

import { cn } from '@utils/cn';

const TooltipProvider = TooltipPrimitive.Provider;

const Tooltip = TooltipPrimitive.Root;

const TooltipTrigger = TooltipPrimitive.Trigger;

const TooltipPortal = TooltipPrimitive.Portal;

const TooltipArrow = forwardRef<
ElementRef<typeof TooltipPrimitive.Arrow>,
ComponentPropsWithoutRef<typeof TooltipPrimitive.Arrow>
>((props, ref) => (
<TooltipPrimitive.Arrow ref={ref} className={cn('fill-sky-500')} {...props} />
));

TooltipArrow.displayName = 'TooltipArrow';

const TooltipContent = forwardRef<
ElementRef<typeof TooltipPrimitive.Content>,
ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 2, ...props }, ref) => (
<TooltipPrimitive.Content
ref={ref}
sideOffset={sideOffset}
className={cn(
'z-tooltip group max-w-72 overflow-hidden rounded-xl bg-sky-950 px-3 py-2.5 text-xs text-white',
'fade-in',
className
)}
{...props}
/>
));

TooltipContent.displayName = TooltipPrimitive.Content.displayName;

export {
Tooltip as TooltipRoot,
TooltipTrigger,
TooltipPortal,
TooltipContent,
TooltipProvider,
TooltipArrow
};
30 changes: 30 additions & 0 deletions apps/frontend/components/ui/tooltip/Tooltip.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
'use client';

import type { FC, ReactNode } from 'react';

import * as Tooltip from '@components/ui/tooltip/Tooltip.components';

type TooltipProps = {
content: ReactNode;
children: ReactNode;
};

const TooltipComponent: FC<TooltipProps> = ({
children,
content,
...triggerProps
}) => (
<Tooltip.TooltipProvider delayDuration={100}>
<Tooltip.TooltipRoot>
<Tooltip.TooltipTrigger {...triggerProps}>
{children}
</Tooltip.TooltipTrigger>
<Tooltip.TooltipContent side='top' align='center'>
{content}
<Tooltip.TooltipArrow />
</Tooltip.TooltipContent>
</Tooltip.TooltipRoot>
</Tooltip.TooltipProvider>
);

export default TooltipComponent;
8 changes: 7 additions & 1 deletion apps/frontend/messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,13 @@
"global": {
"n_a": "N/A",
"filter_by": "Filter by",
"error_message": "Seems like something went wrong..."
"error_message": "Seems like something went wrong...",
"update_data": "Update data",
"updated_time_ago": "Updated {time} ago",
"updated_tooltip": "We make sure to fetch the data at least once per day to keep everything running smoothly.",
"less_one_minute": "less than one minute",
"minutes_unit": "m",
"hours_unit": "h"
},
"navigation": {
"title": "Enterprise",
Expand Down
1 change: 1 addition & 0 deletions apps/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
"@radix-ui/react-select": "2.0.0",
"@radix-ui/react-slider": "1.1.2",
"@radix-ui/react-slot": "1.0.2",
"@radix-ui/react-tooltip": "1.0.7",
"@tanstack/react-query": "5.18.1",
"@tanstack/react-table": "8.11.8",
"axios": "1.6.5",
Expand Down
35 changes: 35 additions & 0 deletions apps/frontend/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 11 additions & 1 deletion apps/frontend/tailwind.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ const config: Config = {
'radix-collapse-slide-up': 'radix-collapse-slide-up 150ms ease-out',
'spin-infinite': 'spin 2s linear infinite',
'accordion-down': 'accordion-down 0.2s ease-out',
'accordion-up': 'accordion-up 0.2s ease-out'
'accordion-up': 'accordion-up 0.2s ease-out',
'fade-in': 'fade-in 150ms ease-out',
'fade-out': 'fade-out 150ms ease-out'
},
keyframes: {
spin: {
Expand Down Expand Up @@ -143,6 +145,14 @@ const config: Config = {
to: {
height: '0'
}
},
'fade-in': {
'0%': { opacity: '0' },
'100%': { opacity: '1' }
},
'fade-out': {
'0%': { opacity: '1' },
'100%': { opacity: '0' }
}
}
}
Expand Down
39 changes: 39 additions & 0 deletions apps/frontend/utils/hooks/useTimeElapsed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useTranslations } from 'next-intl';
import { useEffect, useState } from 'react';

const ONE_SECOND = 1000;

const useTimeElapsed = (startTime: Date): string => {
const [timeElapsed, setTimeElapsed] = useState<string>('');

const t = useTranslations();

useEffect(() => {
const interval = setInterval(() => {
const currentTime = new Date();
const difference = Math.abs(currentTime.getTime() - startTime.getTime());
const secondsElapsed = Math.floor(difference / 1000);

const m = t('global.minutes_unit');
const h = t('global.hours_unit');

if (secondsElapsed < 60) {
setTimeElapsed(t('global.less_one_minute'));
} else {
const minutesElapsed = Math.floor(secondsElapsed / 60);
if (minutesElapsed < 60) {
setTimeElapsed(`${minutesElapsed}${m}`);
} else {
const hoursElapsed = Math.floor(minutesElapsed / 60);
setTimeElapsed(`${hoursElapsed}${h}`);
}
}
}, ONE_SECOND);

return () => clearInterval(interval);
}, [startTime, t]);

return timeElapsed;
};

export default useTimeElapsed;

1 comment on commit 701fec5

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deploy preview for ebsi-vector-frontend ready!

✅ Preview
https://ebsi-vector-frontend-mk4ox81mc-protokol.vercel.app

Built with commit 701fec5.
This pull request is being automatically deployed with vercel-action

Please sign in to comment.