Skip to content

Commit

Permalink
[front] feat: display entity contexts on comparison page (#1858)
Browse files Browse the repository at this point in the history
Co-authored-by: Adrien Matissart <amatissart@users.noreply.github.com>
  • Loading branch information
GresilleSiffle and amatissart authored Dec 21, 2023
1 parent 15a521b commit b389f1c
Show file tree
Hide file tree
Showing 7 changed files with 264 additions and 23 deletions.
9 changes: 6 additions & 3 deletions frontend/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@
"inactivePollComparisonCannotBeSubmittedOrEdited": "No comparison can be submitted or modified.",
"comparisonCriteria": "Comparison criteria"
},
"entityContext": {
"entityAtheAssociationWouldLikeToGiveYouContext": "<0>{{entityName}} A</0> - The Tournesol association would like to give you some context.",
"entityBtheAssociationWouldLikeToGiveYouContext": "<0>{{entityName}} B</0> - The Tournesol association would like to give you some context.",
"theAssociationWouldLikeToGiveYouContext": "The Tournesol association would like to give you some context on this element.",
"about": "About"
},
"comparisonHelper": {
"hideHelp": "Hide the help",
"showHelp": "Show help for comparisons"
Expand All @@ -109,9 +115,6 @@
"entityContextTextList": {
"whyThisMessage": "Why this message?"
},
"contextsFromOrigin": {
"theAssociationWouldLikeToGiveYouContext": "The Tournesol association would like to give you some context on this element."
},
"entitySelector": {
"newVideo": "Select a new video automatically",
"letTournesolSelectAVideo": "Let Tournesol select a video",
Expand Down
9 changes: 6 additions & 3 deletions frontend/public/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@
"inactivePollComparisonCannotBeSubmittedOrEdited": "Aucune comparaison ne peut être ajoutée ou modifiée.",
"comparisonCriteria": "Critères de comparaison"
},
"entityContext": {
"entityAtheAssociationWouldLikeToGiveYouContext": "<0>{{entityName}} A</0> - L'association Tournesol souhaite vous apporter du contexte.",
"entityBtheAssociationWouldLikeToGiveYouContext": "<0>{{entityName}} B</0> - L'association Tournesol souhaite vous apporter du contexte.",
"theAssociationWouldLikeToGiveYouContext": "L'association Tournesol souhaite vous apporter du contexte sur cet élément.",
"about": "A propos de"
},
"comparisonHelper": {
"hideHelp": "Cacher l'aide",
"showHelp": "Montrer l'aide pour les comparaisons"
Expand All @@ -113,9 +119,6 @@
"entityContextTextList": {
"whyThisMessage": "Pourquoi ce message ?"
},
"contextsFromOrigin": {
"theAssociationWouldLikeToGiveYouContext": "L'association Tournesol souhaite vous apporter du contexte sur cet élément."
},
"entitySelector": {
"newVideo": "Sélectionner une nouvelle vidéo automatiquement",
"letTournesolSelectAVideo": "Laisser Tournesol choisir une vidéo",
Expand Down
36 changes: 34 additions & 2 deletions frontend/src/features/comparisons/Comparison.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
import React, { useState, useEffect, useCallback, useMemo } from 'react';
import React, {
useCallback,
useEffect,
useMemo,
useRef,

Check warning on line 5 in frontend/src/features/comparisons/Comparison.tsx

View workflow job for this annotation

GitHub Actions / test

'useRef' is defined but never used
useState,
} from 'react';
import { useHistory, useLocation } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import { Location } from 'history';
Expand All @@ -17,6 +23,7 @@ import EntitySelector, {
} from 'src/features/entity_selector/EntitySelector';
import { UID_YT_NAMESPACE } from 'src/utils/constants';
import { useCurrentPoll } from 'src/hooks/useCurrentPoll';
import ComparisonEntityContexts from './ComparisonEntityContexts';
import ComparisonHelper from './ComparisonHelper';

export const UID_PARAMS: { vidA: string; vidB: string } = {
Expand Down Expand Up @@ -72,11 +79,14 @@ const Comparison = ({
autoFillSelectorA = false,
autoFillSelectorB = false,
}: Props) => {
const { t } = useTranslation();
const { t, i18n } = useTranslation();
const currentLang = i18n.resolvedLanguage;

const history = useHistory();
const location = useLocation();
const { showSuccessAlert, displayErrorsFrom } = useNotifications();
const { name: pollName } = useCurrentPoll();

const [isLoading, setIsLoading] = useState(true);

const [initialComparison, setInitialComparison] =
Expand Down Expand Up @@ -144,6 +154,25 @@ const Comparison = ({
});
}, [pollName, uidA, uidB, selectorA.uid, selectorB.uid]);

/**
* When the UI language changes, refresh the ratings to retrieve the
* corresponding localized entity contexts.
*/
useEffect(() => {
if (isLoading) {
return;
}

if (selectorA.uid) {
setSelectorA((value) => ({ ...value, ratingIsExpired: true }));
}

if (selectorB.uid) {
setSelectorB((value) => ({ ...value, ratingIsExpired: true }));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currentLang]);

const onSubmitComparison = async (c: ComparisonRequest) => {
try {
if (initialComparison) {
Expand Down Expand Up @@ -250,6 +279,9 @@ const Comparison = ({
>
<ComparisonHelper />
</Grid>
<Grid item xs={12}>
<ComparisonEntityContexts selectorA={selectorA} selectorB={selectorB} />
</Grid>
<Grid
item
xs={12}
Expand Down
105 changes: 105 additions & 0 deletions frontend/src/features/comparisons/ComparisonEntityContexts.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import React from 'react';
import { Trans, useTranslation } from 'react-i18next';

import { Grid, useTheme } from '@mui/material';

import EntityContextBox from 'src/features/entity_context/EntityContextBox';
import { SelectorValue } from 'src/features/entity_selector/EntitySelector';
import { useCurrentPoll } from 'src/hooks';
import { getEntityName } from 'src/utils/constants';

interface EntityContextBoxProps {
selectorA: SelectorValue;
selectorB: SelectorValue;
}

const ComparisonEntityContextsItem = ({
selector,
altAssociationDisclaimer,
}: {
selector: SelectorValue;
altAssociationDisclaimer?: React.ReactElement;
}) => {
return (
<>
{selector.rating && selector.uid && selector.rating.entity_contexts && (
<EntityContextBox
uid={selector.uid}
contexts={selector.rating.entity_contexts}
entityName={selector.rating?.entity?.metadata?.name}
altAssociationDisclaimer={altAssociationDisclaimer}
collapsible={true}
/>
)}
</>
);
};

const ComparisonEntityContexts = ({
selectorA,
selectorB,
}: EntityContextBoxProps) => {
const theme = useTheme();

const { t } = useTranslation();
const { name: pollName } = useCurrentPoll();

const entityName = getEntityName(t, pollName);

return (
<Grid
container
spacing={1}
sx={{
'span.primary': {
color: theme.palette.secondary.main,
fontWeight: 'bold',
textTransform: 'capitalize',
},
}}
>
{selectorA.uid === selectorB.uid ? (
<Grid item xs={12}>
<ComparisonEntityContextsItem selector={selectorA} />
</Grid>
) : (
<>
<Grid item xs={12} sm={12} md={6}>
<ComparisonEntityContextsItem
selector={selectorA}
altAssociationDisclaimer={
<strong>
<Trans
t={t}
i18nKey="entityContext.entityAtheAssociationWouldLikeToGiveYouContext"
>
<span className="primary">{{ entityName }} A</span> - The
Tournesol association would like to give you some context.
</Trans>
</strong>
}
/>
</Grid>
<Grid item xs={12} sm={12} md={6}>
<ComparisonEntityContextsItem
selector={selectorB}
altAssociationDisclaimer={
<strong>
<Trans
t={t}
i18nKey="entityContext.entityBtheAssociationWouldLikeToGiveYouContext"
>
<span className="primary">{{ entityName }} B</span> - The
Tournesol association would like to give you some context.
</Trans>
</strong>
}
/>
</Grid>
</>
)}
</Grid>
);
};

export default ComparisonEntityContexts;
94 changes: 79 additions & 15 deletions frontend/src/features/entity_context/EntityContextBox.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import { Link as RouterLink } from 'react-router-dom';
import { useTranslation } from 'react-i18next';
import linkifyStr from 'linkify-string';
Expand All @@ -7,23 +7,39 @@ import {
Alert,
AlertTitle,
Box,
Collapse,
Divider,
IconButton,
Link,
SxProps,
Typography,
} from '@mui/material';
import { KeyboardArrowDown, KeyboardArrowUp } from '@mui/icons-material';

import { EntityContext, OriginEnum } from 'src/services/openapi';
import {
getCollapsedState,
setCollapsedState,
} from 'src/utils/entityContexts/collapsed';

interface EntityContextBoxProps {
uid: string;
contexts: Array<EntityContext>;
// If set, display the entity name before the contexts.
entityName?: string;
// If true the contexts can be collapsed.
collapsible?: boolean;
// Replace the default association disclaier.
altAssociationDisclaimer?: React.ReactElement;
}

interface EntityContextListProps {
uid: string;
origin_?: OriginEnum;
contexts: Array<EntityContext>;
entityName?: string;
collapsible?: boolean;
diclaimer?: React.ReactElement;
}

interface EntityContextTextListProps {
Expand Down Expand Up @@ -78,9 +94,21 @@ const EntityContextList = ({
uid,
contexts,
origin_,
diclaimer,
entityName,
collapsible,
}: EntityContextListProps) => {
const { t } = useTranslation();

const [displayText, setDisplayText] = useState(
collapsible ? !getCollapsedState(uid) : true
);

const toggleDisplayText = (previousState: boolean) => {
setCollapsedState(uid, previousState);
setDisplayText(!previousState);
};

const infos = contexts.filter((ctx) => !ctx.unsafe);
const warnings = contexts.filter((ctx) => ctx.unsafe);

Expand All @@ -96,25 +124,58 @@ const EntityContextList = ({
<Alert
id="entity-context"
severity={entityHasWarnings ? 'warning' : 'info'}
sx={alertSx}
sx={{
'.MuiAlert-message': { width: '100%' },
...alertSx,
}}
>
<AlertTitle>
<strong>
{origin_ === OriginEnum.ASSOCIATION &&
t('contextsFromOrigin.theAssociationWouldLikeToGiveYouContext')}
</strong>
</AlertTitle>

<EntityContextTextList
uid={uid}
origin_={origin_}
contexts={entityHasWarnings ? warnings : infos}
/>
<Box display="flex" justifyContent="space-between">
<AlertTitle>
{diclaimer ? (
diclaimer
) : (
<strong>
{origin_ === OriginEnum.ASSOCIATION &&
t('entityContext.theAssociationWouldLikeToGiveYouContext')}
</strong>
)}
</AlertTitle>

{collapsible && (
<IconButton
aria-label="Show context"
onClick={() => {
toggleDisplayText(displayText ? true : false);
}}
>
{displayText ? <KeyboardArrowUp /> : <KeyboardArrowDown />}
</IconButton>
)}
</Box>

<Collapse in={displayText}>
{entityName && (
<Typography paragraph variant="body2" fontStyle="italic">
{t('entityContext.about')} « {entityName} »
</Typography>
)}
<EntityContextTextList
uid={uid}
origin_={origin_}
contexts={entityHasWarnings ? warnings : infos}
/>
</Collapse>
</Alert>
);
};

const EntityContextBox = ({ uid, contexts }: EntityContextBoxProps) => {
const EntityContextBox = ({
uid,
contexts,
entityName,
altAssociationDisclaimer,
collapsible = false,
}: EntityContextBoxProps) => {
const associationContexts = contexts.filter(
(ctx) => ctx.origin === OriginEnum.ASSOCIATION
);
Expand All @@ -127,6 +188,9 @@ const EntityContextBox = ({ uid, contexts }: EntityContextBoxProps) => {
uid={uid}
origin_={OriginEnum.ASSOCIATION}
contexts={associationContexts}
diclaimer={altAssociationDisclaimer}
entityName={entityName}
collapsible={collapsible}
/>
</Box>
)}
Expand Down
1 change: 1 addition & 0 deletions frontend/src/features/entity_selector/EntitySelector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@ const EntitySelectorInnerAuth = ({
<Typography
variant="h6"
color="secondary"
fontWeight="bold"
sx={{ '&:first-letter': { textTransform: 'capitalize' } }}
>
{title}
Expand Down
Loading

0 comments on commit b389f1c

Please sign in to comment.