Browse Source

fix : request for next dua parts sends after scroling to buttom

fix : audio plays even if it is not synced
master
sina_sajjadi 2 weeks ago
parent
commit
68d3f13eff
  1. 9
      src/components/context/audio-conext.tsx
  2. 1
      src/components/language-switcher.tsx
  3. 1
      src/components/layout/sidebar.tsx
  4. 1
      src/components/modals/modal-manager.tsx
  5. 1
      src/components/modals/modal.tsx
  6. 1
      src/components/sidebar/tabs.tsx
  7. 1
      src/components/ui/search-duas.tsx
  8. 5
      src/components/utils/colorize-vowels.tsx
  9. 4
      src/pages/_app.tsx
  10. 121
      src/pages/duas/[slug].tsx
  11. 7
      tailwind.config.ts

9
src/components/context/audio-conext.tsx

@ -48,7 +48,7 @@ export const AudioProvider: React.FC<{ children: ReactNode }> = ({
children,
}) => {
const audioRef = useRef<HTMLAudioElement | null>(null);
const partRefs = useRef<(HTMLDivElement | null)[]>([]);
let partRefs = useRef<(HTMLDivElement | null)[]>([]);
const [audios, setAudios] = useState<Audio | null>({});
const [audio, setAudio] = useState<Audio | null>({});
@ -62,12 +62,6 @@ export const AudioProvider: React.FC<{ children: ReactNode }> = ({
`web/mafatih/${id}/audios/`
);
console.log(
"Audio Response:",
audioResponse.data.results,
"selectedReciter:",
selectedReciter
);
setAudios(audioResponse.data.results);
let selectedAudio: Audio | undefined;
@ -123,7 +117,6 @@ export const AudioProvider: React.FC<{ children: ReactNode }> = ({
setSelectedReciter,
lastPart , setLastPart
};
console.log(audios);
return (
<AudioContext.Provider value={value}>{children}</AudioContext.Provider>

1
src/components/language-switcher.tsx

@ -161,7 +161,6 @@ const LanguageSwitcher: React.FC = () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, []);
console.log(languages);
return (
<div className="relative inline-block font-sans" ref={wrapperRef}>

1
src/components/layout/sidebar.tsx

@ -6,7 +6,6 @@ function SideBar() {
const router = useRouter();
const params = useParams();
const slug = params?.slug as string;
console.log(router);
if (router.pathname.includes("/about") || router.pathname.includes("/last-read")) {
return null;

1
src/components/modals/modal-manager.tsx

@ -16,7 +16,6 @@ const SearchModal = dynamic(() => import("@/components/modals/search-modal"));
const ManagedModal: React.FC = () => {
const { displayModal, closeModal, modalView } = useUI();
console.log(modalView);
return (
<Modal rootClassName="bottom" variant="bottom" open={displayModal} onClose={closeModal}>

1
src/components/modals/modal.tsx

@ -64,7 +64,6 @@ export default function Modal({
clearAllBodyScrollLocks();
};
}, [open]);
console.log(children);

1
src/components/sidebar/tabs.tsx

@ -31,7 +31,6 @@ const Tabs = () => {
setPath((prev) => {
const newPath = [...prev]; // Create a shallow copy of the array
newPath.splice(index + 1); // Remove elements starting from index + 1
console.log(newPath);
return newPath; // Return the updated array
});

1
src/components/ui/search-duas.tsx

@ -53,7 +53,6 @@ const SearchDuas: React.FC = () => {
setResults(res.data.results);
setIsLoading(false);
// Optionally, you can handle the response here
// console.log(res);
})
.catch((err) => {
console.error("Error fetching search results:", err);

5
src/components/utils/colorize-vowels.tsx

@ -1,6 +1,5 @@
const colorizeVowels = (text: string) => {
// Normalize text to decomposed form (NFD)
const normalizedText = text.normalize("NFD");
// Function to remove vowels/diacritics
const removeDiacritics = (str: string) =>
@ -10,11 +9,11 @@ const colorizeVowels = (text: string) => {
<div className="relative text-rendering-optimize-speed">
{/* Bottom layer: Full text with vowels in orange */}
<div className="absolute top-0 right-0 text-[#EB6E57] font-[UthmanTaha]">
{normalizedText}
{text}
</div>
{/* Top layer: Text without vowels in black */}
<div className="relative text-black font-[UthmanTaha]">
{removeDiacritics(normalizedText)}
{removeDiacritics(text)}
</div>
</div>
);

4
src/pages/_app.tsx

@ -17,7 +17,6 @@ const rtlLanguages = ["ar", "ur", "fa", "ks", "tg", "bn"];
function App({ Component, pageProps }: AppProps) {
const isRtl = rtlLanguages.includes(pageProps?._nextI18Next?.initialLocale) || false;
console.log(isRtl);
return (
<FontSettingsProvider>
@ -29,7 +28,8 @@ console.log(isRtl);
<div className="m-auto lg:p-6">
<div className="flex m-auto max-w-[1440px] flex-col lg:flex-row lg:gap-6 relative">
<SideBar />
<main className={`w-full`}>
<main
className={`w-full`}>
<Component {...pageProps} />
</main>
</div>

121
src/pages/duas/[slug].tsx

@ -1,4 +1,3 @@
// components/DuaComponent.tsx
import React, { useEffect, useRef, useState, useCallback } from "react";
import Image from "next/image";
import SettingIcon from "../../../public/assets/images/WhiteSetting.svg";
@ -16,8 +15,6 @@ import { useFontSettingsContext } from "@/components/context/font-setting-contex
import { useAudio } from "@/components/context/audio-conext";
import { serverSideTranslations } from "next-i18next/serverSideTranslations";
// Define the Dua interface
interface Dua {
id: number;
@ -30,14 +27,14 @@ interface Dua {
// Define the structure for audio synchronization data
interface AudioSyncData {
id: number;
duration: [number, number][];
duration: [number, number][]; // Start and end time in seconds
}
// Define the Audio interface
// Define the API response structure
// Define the API response structure for Dua parts
interface DuaPartsResponse {
results: Dua[];
next: string;
count: number;
}
const DuaComponent: React.FC<DuaComponentProps> = ({
@ -46,11 +43,11 @@ const DuaComponent: React.FC<DuaComponentProps> = ({
}) => {
const params = useParams();
const slug = (params?.slug as string) ?? SelectedDua;
console.log(SelectedDua);
const router = useRouter();
const { openSetting, openAudio } = useUI();
const { audioRef, partRefs, getAudio, audio, setLastPart } = useAudio();
console.log("Audio Ref:", audioRef.current);
const [scrollPosition, setScrollPosition] = useState(0);
const [fetching, setFetching] = useState(false); // Track if data is being fetched
// Use the shared context for font settings
const { fontSettings } = useFontSettingsContext();
@ -58,41 +55,54 @@ const DuaComponent: React.FC<DuaComponentProps> = ({
// State hooks
const [duaParts, setDuaParts] = useState<Dua[]>([]);
const [recitingPart, setRecitingPart] = useState<Dua | null>(null);
const [loading, setLoading] = useState(false);
// Audio reference
// Fetch Dua parts and audio
// Use useCallback to memoize fetchData so it doesn’t change between renders
const fetchData = useCallback(async (nextPage) => {
if (!slug || fetching) return; // Prevent fetching if data is already being fetched
// Refs to track each part
const id = slug.split("-").pop();
if (!id) return;
// Fetch Dua parts and audio
useEffect(() => {
if (!slug) return;
const fetchData = async () => {
const id = slug.split("-").pop();
if (!id) return;
try {
// Fetching dua parts
const duaResponse = await http.get<DuaPartsResponse>(
`web/mafatih-duas/${id}/parts/`
);
setDuaParts(duaResponse.data.results);
} catch (error) {
console.error("Error fetching Dua parts:", error);
// Optionally, set an error state here
}
setFetching(true); // Set fetching to true when data starts fetching
// Reset the duaParts state when the slug changes
const offset = nextPage ? duaParts.length : 0;
try {
setLoading(true);
// Fetch the data
const duaResponse = await http.get<DuaPartsResponse>(
`web/mafatih-duas/${id}/parts/?offset=${offset}`
);
// Append the new results to the existing duaParts
setDuaParts((prev) => [...prev, ...duaResponse.data.results]);
} catch (error) {
console.error("Error fetching Dua parts:", error);
} finally {
setLoading(false);
setFetching(false); // Reset fetching state after fetching is done
}
getAudio(id);
}, [slug, fetching, duaParts, getAudio]); // Dependencies for fetchData
getAudio(id);
};
fetchData();
}, [slug]);
// Use the memoized fetchData in the effect hook
useEffect(() => {
setDuaParts([]); // Reset Dua parts when slug changes
fetchData(false);
}, [slug]); // Only slug changes should trigger this effect
// Play audio from a specific part
const playAudio = useCallback(
(part: Dua) => {
if (!Object.keys(audio).length) return;
console.log(part);
const selectedAudio = audio.audio_sync_data.find(
(item) => item.id === part.id
@ -105,13 +115,15 @@ const DuaComponent: React.FC<DuaComponentProps> = ({
audioRef.current.play().catch((error) => {
console.error("Error playing audio:", error);
});
return;
}
openAudio();
audioRef.current.play().catch((error) => {
console.error("Error playing audio:", error);
});
},
[audio]
);
console.log(audio);
console.log(fontSettings.arabicRange);
// Handle audio end to scroll to the next part
const handleAudioEnd = useCallback(() => {
@ -145,6 +157,7 @@ const DuaComponent: React.FC<DuaComponentProps> = ({
setRecitingPart(currentRecitingPart);
}, [audio, duaParts]);
// Process the slug into a more readable format
function processSlug(slug: string): string {
if (!slug) return "";
@ -205,14 +218,24 @@ const DuaComponent: React.FC<DuaComponentProps> = ({
}
}, [recitingPart, duaParts]);
const handleScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {
const target = e.currentTarget;
const isBottom = target.scrollHeight - target.scrollTop === target.clientHeight;
if (isBottom && !fetching) { // Only fetch when not already fetching
fetchData(true);
}
setScrollPosition(target.scrollTop); // Update scroll position
}, [fetching]);
if (!slug) {
return null; // Handling the case where slug is not available
}
console.log(audioRef.current);
return (
<div
onScroll={handleScroll} // Add the onScroll event listener here
className={`rounded-3xl overflow-y-auto flex-grow h-[calc(100vh-130px)] lg:bg-[#F5F5F5] lg:p-6 lg:rounded-3xl ${
!slug && "hidden lg:flex"
}`}
@ -255,9 +278,7 @@ const DuaComponent: React.FC<DuaComponentProps> = ({
<div className="p-3 bg-white rounded-3xl">
{item.text && (
<div
className={`mb-4 text-right ${
!fontSettings.arabic && "hidden"
}`}
className={`mb-4 text-right ${!fontSettings.arabic && "hidden"}`}
style={{
fontSize: `${25 * (fontSettings.arabicRange / 100)}px`,
}}
@ -267,13 +288,9 @@ const DuaComponent: React.FC<DuaComponentProps> = ({
)}
{item.local_alpha && (
<p
className={`text-sm font-normal mb-4 ${
!fontSettings.transliteration && "hidden"
}`}
className={`text-sm font-normal mb-4 ${!fontSettings.transliteration && "hidden"}`}
style={{
fontSize: `${
14 * (fontSettings.transliterationRange / 100)
}px`,
fontSize: `${14 * (fontSettings.transliterationRange / 100)}px`,
}}
>
{item.local_alpha}
@ -281,9 +298,7 @@ const DuaComponent: React.FC<DuaComponentProps> = ({
)}
{item.translation && (
<p
className={`text-sm font-normal border-t pt-4 ${
!fontSettings.translation && "hidden"
}`}
className={`text-sm font-normal border-t pt-4 ${!fontSettings.translation && "hidden"}`}
style={{
fontSize: `${14 * (fontSettings.translationRange / 100)}px`,
}}
@ -297,7 +312,6 @@ const DuaComponent: React.FC<DuaComponentProps> = ({
</p>
)}
{/* Play button to start audio from specific time */}
{audio && !!Object.keys(audio)?.length && (
<button
onClick={() => playAudio(item)}
@ -324,10 +338,11 @@ const DuaComponent: React.FC<DuaComponentProps> = ({
);
};
// Fetching server-side translations for multi-language support
export async function getServerSideProps({ locale }: { locale: string }) {
return {
props: {
...(await serverSideTranslations(locale, ['common'])), // Load translations for 'common' namespace
...(await serverSideTranslations(locale, ["common"])), // Load translations for 'common' namespace
},
};
}

7
tailwind.config.ts

@ -26,10 +26,13 @@ export default {
addUtilities(
{
'.text-rendering-optimize-speed': {
'text-rendering': 'optimizeSpeed',
'text-rendering': 'geometricPrecision',
},
'.no-ligatures': {
'font-variant-ligatures': 'none', // Add this utility
},
},
['responsive', 'hover'] // Make this available for responsive and hover variants
['responsive', 'hover'] // Ensure this utility is available for responsive and hover variants
);
},
],

Loading…
Cancel
Save