Skip to content
This repository has been archived by the owner on Aug 23, 2024. It is now read-only.

B/bulk bugfixes #167

Merged
merged 6 commits into from
Feb 27, 2024
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
8 changes: 4 additions & 4 deletions components/blocks/language-selector.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useTranslation } from 'react-i18next';
import { IconButton, Menu, MenuButton, MenuItem, MenuList } from '@chakra-ui/react';
import { useCallback, useEffect } from 'react';
import { useCallback, useEffect, useMemo } from 'react';
import { HiLanguage } from 'react-icons/hi2';
import LanguageDetector from 'i18next-browser-languagedetector';

Expand All @@ -18,20 +18,20 @@ const languages: LanguageOption[] = [
const LanguageSelector = ({ bg = 'transparent', size, color }: { bg?: string; size?: string; color?: string }) => {
const { i18n } = useTranslation();

const languageDetector = new LanguageDetector();
const languageDetector = useMemo(() => new LanguageDetector(), []);

useEffect(() => {
languageDetector.init();
const lng = languageDetector.detect();
i18n.changeLanguage(typeof lng === 'string' ? lng : lng[0]);
}, []);
}, [i18n, languageDetector]);

const handleLanguageChange = useCallback(
(languageCode: string) => {
i18n.changeLanguage(languageCode);
languageDetector.cacheUserLanguage(languageCode);
},
[i18n]
[i18n, languageDetector]
);

return (
Expand Down
89 changes: 42 additions & 47 deletions components/pages/app/footer.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,52 @@
import React from 'react';
import styled, { useTheme } from 'styled-components';
import Link from 'next/link';
import i18n from '../../../i18n';
import { HOME_PATH } from '@const/routes';
import { useTranslation } from 'react-i18next';

export const Footer = () => {
const theme = useTheme();
const { i18n } = useTranslation();

const LINKS: HeaderLink[] = [
{
url: 'https://blog.aragon.org/vocdoni/',
name: i18n.t('links.blog'),
external: true,
logged: true,
guest: true,
},
{
url: 'https://developer.vocdoni.io',
name: i18n.t('links.docs'),
external: true,
logged: true,
guest: true,
},
{
url: 'https://discord.gg/sM7UhAGY53',
name: i18n.t('links.help'),
external: true,
logged: true,
guest: true,
},
{
// url: ABOUT_PATH,
url: 'https://vocdoni.io',
name: i18n.t('links.about'),
external: false,
logged: false,
guest: true,
},
{
url: 'https://discord.gg/sQCxgYs',
name: i18n.t('links.support'),
external: true,
logged: true,
guest: false,
},
];

const links = LINKS.filter((link) => link.guest);

return (
Expand Down Expand Up @@ -119,49 +160,3 @@ interface HeaderLink {
logged?: boolean;
guest?: boolean;
}

const LINKS: HeaderLink[] = [
// {
// url: PRIVACY_PATH,
// name: i18n.t("links.privacy_policy"),
// external: true,
// logged: true,
// guest: true
// },
{
url: 'https://blog.vocdoni.io',
name: i18n.t('links.blog'),
external: true,
logged: true,
guest: true,
},
{
url: 'https://docs.vocdoni.io',
name: i18n.t('links.docs'),
external: true,
logged: true,
guest: true,
},
{
url: 'https://help.aragon.org/collection/54-vocdoni-user-guide',
name: i18n.t('links.help'),
external: true,
logged: true,
guest: true,
},
{
// url: ABOUT_PATH,
url: 'https://vocdoni.io',
name: i18n.t('links.about'),
external: false,
logged: false,
guest: true,
},
{
url: 'https://discord.gg/sQCxgYs',
name: i18n.t('links.support'),
external: true,
logged: true,
guest: false,
},
];
48 changes: 27 additions & 21 deletions components/pages/app/page-templates/list-page-jump-to.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Column, ListCardContainer } from '@components/elements/grid';
import { useTranslation } from 'react-i18next';
import { ReactNode, useEffect, useState } from 'react';
import { ReactNode, useCallback, useEffect, useState } from 'react';
import { renderSkeleton } from './list-page';
import { FlexAlignItem, FlexContainer, FlexJustifyContent } from '@components/elements/flex';
import { Else, If, Then } from 'react-if';
Expand All @@ -14,7 +14,7 @@
totalElementsCount: number;
pageSize?: number;
// Function that render map of elements
renderElementFunction: (element: any, i: number) => ReactNode;

Check warning on line 17 in components/pages/app/page-templates/list-page-jump-to.tsx

View workflow job for this annotation

GitHub Actions / node-tests-and-build

Unexpected any. Specify a different type

Check warning on line 17 in components/pages/app/page-templates/list-page-jump-to.tsx

View workflow job for this annotation

GitHub Actions / node-tests-and-build

Unexpected any. Specify a different type
currentPage: number;
setCurrentPage: (x: number) => void;
}
Expand Down Expand Up @@ -98,30 +98,36 @@
// Set loading
useEffect(() => {
setLoading(loadingElements || dataPagination == null || lastElement == null);
}, [loadingElements, dataPagination]);
}, [loadingElements, dataPagination, lastElement]);

const getFirstPageIndex = (page) => {
const index = lastElement - page * pageSize;
return index < 0 ? 0 : index;
};
const getFirstPageIndex = useCallback(
(page) => {
const index = lastElement - page * pageSize;
return index < 0 ? 0 : index;
},
[lastElement, pageSize]
);

// Get the page where the block are you searching is
const getPageFromPosition = () => {
const getPageFromPosition = useCallback(() => {
const totalPages = Math.ceil(lastElement / pageSize);
return totalPages - Math.ceil(jumpTo / pageSize);
};
}, [jumpTo, lastElement, pageSize]);

const jumpToPosition = (newPos) => {
// Calculate new position
// const jumpToPosition = (jumpTo + 1) - pageSize
// But if paginator is used, page can change but the filter could be still set
// As we are using the paginator with pages instead of with positions, we have to handle
// the fact that somebody jump to a position and then advance the page.
// todo(ritmo): use paginator based on positions and not on pages for easy use.
const pageOfPosition = getPageFromPosition();
const offset = () => newPos + 1 - getFirstPageIndex(pageOfPosition);
setDataPagination(getFirstPageIndex(currentPage) + offset() - pageSize);
};
const jumpToPosition = useCallback(
(newPos) => {
// Calculate new position
// const jumpToPosition = (jumpTo + 1) - pageSize
// But if paginator is used, page can change but the filter could be still set
// As we are using the paginator with pages instead of with positions, we have to handle
// the fact that somebody jump to a position and then advance the page.
// todo(ritmo): use paginator based on positions and not on pages for easy use.
const pageOfPosition = getPageFromPosition();
const offset = () => newPos + 1 - getFirstPageIndex(pageOfPosition);
setDataPagination(getFirstPageIndex(currentPage) + offset() - pageSize);
},
[currentPage, getFirstPageIndex, getPageFromPosition, pageSize, setDataPagination]
);

// Jump to height on filter
useEffect(() => {
Expand All @@ -136,7 +142,7 @@
} else {
setCurrentPage(1);
}
}, [jumpTo]);
}, [currentPage, getPageFromPosition, jumpTo, jumpToPosition]);

// When current page changed get next blocks
useEffect(() => {
Expand All @@ -146,7 +152,7 @@
jumpToPosition(jumpTo);
} else setDataPagination(getFirstPageIndex(currentPage));
}
}, [currentPage, lastElement]);
}, [currentPage, getFirstPageIndex, jumpTo, jumpToPosition, lastElement, setDataPagination]);

return {
loading,
Expand Down
12 changes: 6 additions & 6 deletions components/pages/blocks/components/BlockFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next';
import { InputSearch } from '@components/elements/inputs';
import { InlineFlex } from '@components/elements/flex';
import { DivWithMarginChildren } from '@components/elements/styled-divs';
import { useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { FilterForm } from '@components/pages/app/page-templates/filter-form';
import { DELAY_BOUNCE_TIME } from '@const/filters';

Expand All @@ -18,21 +18,21 @@ export const BlocksFilter = ({ setFilter }: { setFilter: (IFilterBlocks) => void

const [tempFilter, setTempFilter] = useState<IFilterBlocks>({});

const resetFilter = () => {
const resetFilter = useCallback(() => {
setTempFilter({});
setSearchTermIT('');
};
}, []);

const _onEnableFilter = () => {
const _onEnableFilter = useCallback(() => {
setFilter(Object.assign({}, tempFilter));
};
}, [setFilter, tempFilter]);

useEffect(() => {
const delayDebounceFn = setTimeout(() => {
_onEnableFilter();
}, DELAY_BOUNCE_TIME);
return () => clearTimeout(delayDebounceFn);
}, [tempFilter]);
}, [_onEnableFilter, tempFilter]);

return (
<FilterForm onEnableFilter={_onEnableFilter}>
Expand Down
14 changes: 11 additions & 3 deletions components/pages/elections/components/ElectionCard.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { ProcessTimeLeft } from '@components/blocks/process_time_left';
import { getPath } from '@components/pages/app/components/get-links';
import { CustomElectionStatusBadge } from '@components/pages/elections/components/ElectionStatusBadge';
import { AnonVoteBadge, ArchivedBadge } from '@components/pages/elections/components/ElectionTypeBadge';
import {
AnonVoteBadge,
ArchivedBadge,
InvalidElectionBadge,
} from '@components/pages/elections/components/ElectionTypeBadge';
import { PROCESS_DETAILS } from '@const/routes';
import useExtendedElection from '@hooks/use-extended-election';
import { ElectionProvider, OrganizationProvider } from '@vocdoni/react-providers';
import { IElectionSummary, PublishedElection } from '@vocdoni/sdk';
import { IElectionSummary, InvalidElection, PublishedElection } from '@vocdoni/sdk';
import styled from 'styled-components';
import {
BodyWrapper,
Expand Down Expand Up @@ -40,13 +44,17 @@ const InnerCard = ({ electionId, electionSummary, hideEntity, ...rest }: Process
const title = election?.title?.default ?? electionId;
const organizationId = election?.organizationId ?? electionSummary?.organizationId ?? null;
const status = election?.status ?? PublishedElection.getStatus(electionSummary?.status, startDate) ?? null;
const isInvalid = election instanceof InvalidElection;

const loading = electionLoading && !electionSummary;

const Top = () => (
<TopWrapper>
{isInvalid && <InvalidElectionBadge />}
{election?.fromArchive ? <ArchivedBadge /> : <CustomElectionStatusBadge status={status} />}
{!election?.fromArchive && <ProcessTimeLeft status={status} endDate={endDate} startDate={startDate} />}
{!isInvalid && !election?.fromArchive && (
<ProcessTimeLeft status={status} endDate={endDate} startDate={startDate} />
)}
{anonymous && <AnonVoteBadge />}
</TopWrapper>
);
Expand Down
9 changes: 9 additions & 0 deletions components/pages/elections/components/ElectionTypeBadge.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,12 @@ export const ArchivedBadge = () => {
const { i18n } = useTranslation();
return <CustomTag bg={'#68672e'}>{i18n.t('vote.badge.archived')}</CustomTag>;
};

export const InvalidElectionBadge = () => {
const { i18n } = useTranslation();
return (
<CustomTag bg={'#c9eaf8'} color={'#f17c7c'}>
{i18n.t('vote.badge.invalid')}
</CustomTag>
);
};
14 changes: 9 additions & 5 deletions components/pages/elections/details/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,22 @@ import useExtendedElection from '@hooks/use-extended-election';
import { DateDiffType, localizedDateDiff, localizedStartEndDateDiff } from '@lib/date';
import { colors } from '@theme/colors';
import { ElectionDescription } from '@vocdoni/chakra-components';
import { CensusTypeEnum, ElectionStatus } from '@vocdoni/sdk';
import { CensusTypeEnum, ElectionStatus, InvalidElection } from '@vocdoni/sdk';
import { useTranslation } from 'react-i18next';
import styled from 'styled-components';
import { CensusOriginBadge } from '../components/ElectionCensusOrigin-badge';
import { EnvelopeExplorer } from '../components/ElectionEnvelopeExplorer';
import { EncryptionKeys } from '../components/ElectionKeys';
import { ProcessModeBadge } from '../components/ElectionProcessmodeBadge';
import { AnonVoteBadge, ElectionTypeBadge, ArchivedBadge } from '../components/ElectionTypeBadge';
import { AnonVoteBadge, ArchivedBadge, ElectionTypeBadge, InvalidElectionBadge } from '../components/ElectionTypeBadge';
import { ResultsCard } from '../components/ResultsCard';

const ProcessesDetailPage = () => {
const { election, electionRaw } = useExtendedElection();
const dateDiffStr = resolveLocalizedDateDiff(election.startDate, election.endDate, election.status);
const id = election.id;
const organizationId = election.organizationId;
const isInvalid = election instanceof InvalidElection;

const { i18n } = useTranslation();

Expand All @@ -53,9 +54,11 @@ const ProcessesDetailPage = () => {
</Typography>
<CustomElectionStatusBadge status={election.status} />
</FlexRowWrapper>
<Typography variant={TypographyVariant.Small} color={colors.lightText}>
{dateDiffStr}
</Typography>
{!isInvalid && (
<Typography variant={TypographyVariant.Small} color={colors.lightText}>
{dateDiffStr}
</Typography>
)}
<Typography variant={TypographyVariant.Small} color={colors.lightText}>
<span>{i18n.t('processes.details.created_on')} </span>
<span>{localizedDateDiff(election.startDate)}</span>
Expand All @@ -64,6 +67,7 @@ const ProcessesDetailPage = () => {
{/* Labels and badges */}
<Grid>
<BadgeColumn>
{isInvalid && <InvalidElectionBadge />}
{election.fromArchive && <ArchivedBadge />}
<CensusOriginBadge censusOrigin={CensusTypeEnum[electionRaw.census.censusOrigin as string]} />
<ProcessModeBadge autostart={electionRaw.electionMode.autoStart} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { useTranslation } from 'react-i18next';
import { InputSearch } from '@components/elements/inputs';
import { InlineFlex } from '@components/elements/flex';
import { DivWithMarginChildren } from '@components/elements/styled-divs';
import { useEffect, useState } from 'react';
import { useCallback, useEffect, useState } from 'react';
import { FilterForm } from '@components/pages/app/page-templates/filter-form';
import { DELAY_BOUNCE_TIME } from '@const/filters';

Expand All @@ -23,16 +23,16 @@ export const TransactionsFilter = ({ setFilter }: { setFilter: (IFilterTransacti
setSearchTermIT('');
};

const _onEnableFilter = () => {
const _onEnableFilter = useCallback(() => {
setFilter(Object.assign({}, tempFilter));
};
}, [setFilter, tempFilter]);

useEffect(() => {
const delayDebounceFn = setTimeout(() => {
_onEnableFilter();
}, DELAY_BOUNCE_TIME);
return () => clearTimeout(delayDebounceFn);
}, [tempFilter]);
}, [_onEnableFilter, tempFilter]);

return (
<FilterForm onEnableFilter={_onEnableFilter}>
Expand Down
3 changes: 1 addition & 2 deletions components/pages/verify/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,10 @@ import { DivWithMarginChildren, FakedButton } from '@components/elements/styled-
import { Typography, TypographyVariant } from '@components/elements/typography';
import i18n from '@i18n';
import { colors } from '@theme/colors';
import { ReactNode, useEffect, useState } from 'react';
import { useState } from 'react';
import styled from 'styled-components';
import { TopDiv } from '../app/page-templates/list-page';
import { Button } from '@components/elements/button';
import { useUrlHash } from 'use-url-hash';

const VerifyPage = ({ minified = false, onSubmit }: { minified?: boolean; onSubmit?: (etVoteId: string) => void }) => {
const [etVoteId, setEtVoteId] = useState(''); // Handle edit text state
Expand Down
Loading
Loading