Skip to content

Commit

Permalink
Group Ayah/Translation of Q&A (#2284)
Browse files Browse the repository at this point in the history
* Group Ayah/Translation of Q&A

* Keep code DRY
  • Loading branch information
osamasayed committed Jan 30, 2025
1 parent 70c4a41 commit 40609e4
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 45 deletions.
4 changes: 2 additions & 2 deletions src/components/QuestionAndAnswer/Answer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import styles from './Answer.module.scss';
import AnswerBody from './AnswerBody';
import RangesIndicator from './RangesIndicator';

import VerseAndTranslation from '@/components/Verse/VerseAndTranslation';
import GroupedVerseAndTranslation from '@/components/Verse/GroupedVerseAndTranslation';
import Collapsible from '@/dls/Collapsible/Collapsible';
import ChevronDownIcon from '@/icons/chevron-down.svg';
import { Question } from '@/types/QuestionsAndAnswers/Question';
Expand Down Expand Up @@ -37,7 +37,7 @@ const Answer = ({ question }: AnswerProps) => {
if (!isOpenRenderProp) return null;

return (
<VerseAndTranslation
<GroupedVerseAndTranslation
chapter={rangeStartData.chapter}
from={rangeStartData.verse}
to={rangeEndData.verse}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import React from 'react';

import QuestionsList from '@/components/QuestionAndAnswer/QuestionsList';
import styles from '@/components/QuranReader/ReflectionView/ReflectionBodyContainer/ReflectionBody/ReflectionBody.module.scss';
import VerseAndTranslation from '@/components/Verse/VerseAndTranslation';
import GroupedVerseAndTranslation from '@/components/Verse/GroupedVerseAndTranslation';
import Separator from '@/dls/Separator/Separator';
import { Question } from '@/types/QuestionsAndAnswers/Question';

Expand All @@ -25,7 +25,7 @@ const QuestionsBody: React.FC<Props> = ({
}) => {
return (
<div className={styles.container}>
<VerseAndTranslation
<GroupedVerseAndTranslation
from={Number(selectedVerseNumber)}
to={Number(selectedVerseNumber)}
chapter={Number(selectedChapterId)}
Expand Down
5 changes: 5 additions & 0 deletions src/components/Verse/GroupedVerseAndTranslation.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.container {
display: flex;
flex-direction: column;
gap: var(--spacing-small);
}
84 changes: 84 additions & 0 deletions src/components/Verse/GroupedVerseAndTranslation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/* eslint-disable unicorn/no-array-reduce */
import { useMemo } from 'react';

import styles from './GroupedVerseAndTranslation.module.scss';
import PlainVerseText from './PlainVerseText';

import Error from '@/components/Error';
import TranslationText from '@/components/QuranReader/TranslationView/TranslationText';
import Spinner from '@/dls/Spinner/Spinner';
import useVerseAndTranslation from '@/hooks/useVerseAndTranslation';
import { getVerseWords } from '@/utils/verse';

interface Props {
chapter: number;
from: number;
to: number;
}

const GroupedVerseAndTranslation: React.FC<Props> = (props) => {
const { data, error, mutate, translations, translationFontScale } = useVerseAndTranslation(props);

const allWords = useMemo(() => {
if (!data?.verses) return [];
return data.verses.reduce((acc, verse) => {
return [...acc, ...getVerseWords(verse)];
}, []);
}, [data?.verses]);

const groupedTranslations = useMemo(() => {
if (!data?.verses) return {};
return translations.reduce<Record<number, any>>((acc, translationId: number) => {
const texts = data.verses.reduce((textsAcc, verse) => {
const translation = verse.translations?.find(
(t) => String(t.resourceId) === String(translationId),
);
return translation ? [...textsAcc, translation] : textsAcc;
}, []);

return { ...acc, [translationId]: texts };
}, {});
}, [data?.verses, translations]);

if (error) return <Error error={error} onRetryClicked={mutate} />;
if (!data) return <Spinner />;

return (
<div className={styles.container}>
<div className={styles.arabicSection}>
<div className={styles.arabicVerseContainer}>
<PlainVerseText words={allWords} />
</div>
</div>

<div className={styles.translationsSection}>
{translations.map((translationId: number) => {
const translationGroup = groupedTranslations[translationId];
if (!translationGroup?.length) return null;

const firstTranslation = translationGroup[0];
return (
<div key={`translation-${translationId}`} className={styles.translationGroup}>
<div className={styles.translationContainer}>
<TranslationText
languageId={firstTranslation.languageId}
resourceName={firstTranslation.resourceName}
translationFontScale={translationFontScale}
text={translationGroup
.map((t, index) =>
data.verses.length > 1
? `${t.text} (${data.verses[index].verseNumber})`
: t.text,
)
.join(' ')}
/>
</div>
</div>
);
})}
</div>
</div>
);
};

export default GroupedVerseAndTranslation;
46 changes: 5 additions & 41 deletions src/components/Verse/VerseAndTranslation.tsx
Original file line number Diff line number Diff line change
@@ -1,23 +1,11 @@
import useTranslation from 'next-translate/useTranslation';
import { shallowEqual, useSelector } from 'react-redux';
import useSWR from 'swr/immutable';

import Spinner from '../dls/Spinner/Spinner';
import TranslationText from '../QuranReader/TranslationView/TranslationText';

import PlainVerseText from './PlainVerseText';
import styles from './VerseAndTranslation.module.scss';

import Error from '@/components/Error';
import useQcfFont from '@/hooks/useQcfFont';
import { selectQuranReaderStyles } from '@/redux/slices/QuranReader/styles';
import { selectSelectedTranslations } from '@/redux/slices/QuranReader/translations';
import { getDefaultWordFields, getMushafId } from '@/utils/api';
import { makeVersesUrl } from '@/utils/apiPaths';
import { areArraysEqual } from '@/utils/array';
import TranslationText from '@/components/QuranReader/TranslationView/TranslationText';
import Spinner from '@/dls/Spinner/Spinner';
import useVerseAndTranslation from '@/hooks/useVerseAndTranslation';
import { getVerseWords } from '@/utils/verse';
import { fetcher } from 'src/api';
import { VersesResponse } from 'types/ApiResponses';

/**
* Given a verse range
Expand All @@ -34,32 +22,8 @@ interface Props {
to: number;
}

const VerseAndTranslation: React.FC<Props> = ({ chapter, from, to }) => {
const { lang } = useTranslation();
const translations = useSelector(selectSelectedTranslations, areArraysEqual);
const { quranFont, mushafLines, translationFontScale } = useSelector(
selectQuranReaderStyles,
shallowEqual,
);

const mushafId = getMushafId(quranFont, mushafLines).mushaf;
const apiParams = {
...getDefaultWordFields(quranFont),
translationFields: 'resource_name,language_id',
translations: translations.join(','),
mushaf: mushafId,
from: `${chapter}:${from}`,
to: `${chapter}:${to}`,
};

const shouldFetchData = !!from;

const { data, error, mutate } = useSWR<VersesResponse>(
shouldFetchData ? makeVersesUrl(chapter, lang, apiParams) : null,
fetcher,
);

useQcfFont(quranFont, data?.verses ? data.verses : []);
const VerseAndTranslation: React.FC<Props> = (props) => {
const { data, error, mutate, translationFontScale } = useVerseAndTranslation(props);

if (error) return <Error error={error} onRetryClicked={mutate} />;

Expand Down
57 changes: 57 additions & 0 deletions src/hooks/useVerseAndTranslation.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import useTranslation from 'next-translate/useTranslation';
import { shallowEqual, useSelector } from 'react-redux';
import useSWR from 'swr/immutable';

import useQcfFont from '@/hooks/useQcfFont';
import { selectQuranReaderStyles } from '@/redux/slices/QuranReader/styles';
import { selectSelectedTranslations } from '@/redux/slices/QuranReader/translations';
import { getDefaultWordFields, getMushafId } from '@/utils/api';
import { makeVersesUrl } from '@/utils/apiPaths';
import { areArraysEqual } from '@/utils/array';
import { fetcher } from 'src/api';
import { VersesResponse } from 'types/ApiResponses';

interface Props {
chapter: number;
from: number;
to: number;
}

const useVerseAndTranslation = ({ chapter, from, to }: Props) => {
const { lang } = useTranslation();
const translations = useSelector(selectSelectedTranslations, areArraysEqual);
const { quranFont, mushafLines, translationFontScale } = useSelector(
selectQuranReaderStyles,
shallowEqual,
);

const mushafId = getMushafId(quranFont, mushafLines).mushaf;
const apiParams = {
...getDefaultWordFields(quranFont),
translationFields: 'resource_name,language_id',
translations: translations.join(','),
mushaf: mushafId,
from: `${chapter}:${from}`,
to: `${chapter}:${to}`,
};

const shouldFetchData = !!from;

const { data, error, mutate } = useSWR<VersesResponse>(
shouldFetchData ? makeVersesUrl(chapter, lang, apiParams) : null,
fetcher,
);

useQcfFont(quranFont, data?.verses ? data.verses : []);

return {
data,
error,
mutate,
translations,
translationFontScale,
quranFont,
};
};

export default useVerseAndTranslation;

0 comments on commit 40609e4

Please sign in to comment.