diff --git a/src/components/modals/languages-modal.tsx b/src/components/modals/languages-modal.tsx index fa5f35f..6359b65 100644 --- a/src/components/modals/languages-modal.tsx +++ b/src/components/modals/languages-modal.tsx @@ -3,12 +3,98 @@ import { IoMdClose } from "react-icons/io"; import { useUI } from "../context/ui.context"; import { FaCheckCircle } from "react-icons/fa"; import { useTranslation } from "next-i18next"; // Import useTranslation +import { useRouter } from "next/router"; interface Language { code: string; // Assuming each language has a unique ID name: string; } + +const data = [ + { + "name": "English", + "code": "en" + }, + { + "name": "Spanish", + "code": "es" + }, + { + "name": "German", + "code": "de" + }, + { + "name": "Uzbek", + "code": "uz" + }, + { + "name": "Portuguese", + "code": "pt" + }, + { + "name": "Bengali", + "code": "bn" + }, + { + "name": "Chinese", + "code": "zh" + }, + { + "name": "Azerbaijani", + "code": "az" + }, + { + "name": "Urdu", + "code": "ur" + }, + { + "name": "French", + "code": "fr" + }, + { + "name": "Turkish", + "code": "tr" + }, + { + "name": "Indonesian", + "code": "id" + }, + { + "name": "Swahili", + "code": "sw" + }, + { + "name": "Russian", + "code": "ru" + }, + { + "name": "Arabic", + "code": "ar" + }, + { + "name": "Tajik", + "code": "tg" + }, + { + "name": "Persian", + "code": "fa" + }, + { + "name": "Gujarati", + "code": "gu" + }, + { + "name": "Kashmiri", + "code": "ks" + }, + { + "name": "Hausa", + "code": "ha" + } +] + + const LanguageModal = () => { const [languages, setLanguages] = useState([]); const [selectedLanguage, setSelectedLanguage] = useState(""); @@ -16,18 +102,19 @@ const LanguageModal = () => { const [error, setError] = useState(null); const { closeModal } = useUI(); const { t } = useTranslation("common"); // Initialize useTranslation hook for common.json + const router = useRouter(); useEffect(() => { const fetchLanguages = async () => { - try { - setIsLoading(true); - const response = await http.get("v1/languages/"); - setLanguages(response.data); - } catch (err) { - setError(t("failed_to_load_languages")); // Use translation for error message - } finally { + // try { + // setIsLoading(true); + // const response = await http.get("v1/languages/"); + setLanguages(data); + // } catch (err) { + // setError(t("failed_to_load_languages")); // Use translation for error message + // } finally { setIsLoading(false); - } + // } }; fetchLanguages(); @@ -39,8 +126,12 @@ const LanguageModal = () => { }, [t]); // Add t as dependency to ensure it updates with language change const handleLanguageSelect = (code: string) => { - setSelectedLanguage(code); - localStorage.setItem("locale", code); // Persist selection in localStorage + router.push(router.asPath, undefined, { locale: code }).then(() => { + // Optionally you can trigger the language change effect after the page is pushed + setSelectedLanguage(code); + localStorage.setItem("locale", code); // Save the selected language in localStorage + window.location.reload(); + }); }; if (isLoading) { diff --git a/src/components/sidebar/list.tsx b/src/components/sidebar/list.tsx index 2179e6a..e1a6c5b 100644 --- a/src/components/sidebar/list.tsx +++ b/src/components/sidebar/list.tsx @@ -13,13 +13,14 @@ import { useRouter } from "next/navigation"; import colorizeVowels from "../utils/colorize-vowels"; import { formatHijriDate } from "../utils/date-formaters"; import { Category, Dua, ListProps } from "../utils/types"; -import { useTranslation } from "next-i18next"; // Importing the translation hook +import { useTranslation } from "next-i18next"; // Importing the translation hook const List: React.FC = ({ tab, path, setPath, data, setData }) => { const { t } = useTranslation("common"); // Initialize translation hook for "common" namespace const [loading, setLoading] = useState(false); const [currentDhikr, setCurrentDhikr] = useState(""); const [currentTranslation, setCurrentTranslation] = useState(""); + const [error, setError] = useState(null); // State to hold error messages const router = useRouter(); const today = new Date(); const dayOfWeek = new Intl.DateTimeFormat("en-US", { @@ -32,6 +33,7 @@ const List: React.FC = ({ tab, path, setPath, data, setData }) => { locale = localStorage.getItem("locale") || "en"; if (tab === "Today") { setLoading(true); + setError(null); // Reset error state before starting the request http .get("web/mafatih-duas/dhikrs/?today=true") .then((res) => { @@ -47,11 +49,12 @@ const List: React.FC = ({ tab, path, setPath, data, setData }) => { setLoading(false); }) .catch((error) => { + setLoading(false); // Ensure loading state is false if request fails + setError(t("error.fetchDhikrData")); // Display a translated error message console.error("Error fetching Dhikr data:", error); - setLoading(false); }); } - }, [tab, dayOfWeek, locale]); + }, [tab, dayOfWeek, locale, t]); const openCategory = (category: Category) => { setData({ type: "children", data: category.children }); @@ -71,39 +74,49 @@ const List: React.FC = ({ tab, path, setPath, data, setData }) => { useEffect(() => { setData({ type: null, data: [] }); + setError(null); // Reset error state before starting the request if (tab === "Categories") { setLoading(true); - http.get("web/mafatih-categories/").then((res) => { - setData({ type: "Categories", data: res.data }); - setPath([{ name: "", type: "Categories", data: res.data }]); - setLoading(false); - }); + http + .get("web/mafatih-categories/") + .then((res) => { + setData({ type: "Categories", data: res.data }); + setPath([{ name: "", type: "Categories", data: res.data }]); + setLoading(false); + }) + .catch((error) => { + setLoading(false); + setError(t("error.fetchCategories")); // Display a translated error message + console.error("Error fetching categories:", error); + }); } + if (tab === "Today") { - http.get("web/mafatih-duas/?today=true").then((res) => { - setData({ type: null, data: res.data.results }); - }); + http + .get("web/mafatih-duas/?today=true") + .then((res) => { + setData({ type: null, data: res.data.results }); + }) + .catch((error) => { + setError(t("error.fetchTodayDuas")); + console.error("Error fetching today's duas:", error); + }); } - }, [setData, setPath, tab]); + }, [setData, setPath, tab, t]); useEffect(() => { if (data.data.length) { const filteredData = data.data.filter((item: any) => !item.title); // Exclude objects with a "title" filteredData.forEach((category: Category) => { - // Filter out children that do not have a title const hasDua = category.children.filter((item: any) => !item.title); - // Make an HTTP GET request to fetch duas for the current category http .get(`web/mafatih-duas/?category=${category.id}`) .then((res) => { - console.log(res); - let duas = res.data.results; if (duas.length) { - // Deduplicate duas based on their 'id' const uniqueDuasMap = new Map(); duas.forEach((dua: any) => { if (!uniqueDuasMap.has(dua.id)) { @@ -111,20 +124,17 @@ const List: React.FC = ({ tab, path, setPath, data, setData }) => { } }); - // Convert the Map back to an array of unique duas duas = Array.from(uniqueDuasMap.values()); - - // Assign the combined array to category.children category.children = [...hasDua, ...duas]; - // Update the state with the modified filteredData setData((prevState: Category) => ({ ...prevState, - data: filteredData, // Update state with the updated filtered data + data: filteredData, })); } }) .catch((error) => { + setError(t("error.fetchDuasForCategory")); console.error( `Error fetching duas for category ${category.id}:`, error @@ -132,10 +142,14 @@ const List: React.FC = ({ tab, path, setPath, data, setData }) => { }); }); } - }, [path]); + }, [path, t]); if (loading) { - return

{t("loading")}

; {/* Translating the loading message */} + return

{t("loading")}

; // Translating the loading message + } + + if (error) { + return

{error}

; // Displaying the error message } return ( @@ -155,7 +169,8 @@ const List: React.FC = ({ tab, path, setPath, data, setData }) => { />

{t("todayDhikr")} -

{/* Translating the title */} +

{" "} + {/* Translating the title */} diff --git a/src/components/sticky-components/audio-controls.tsx b/src/components/sticky-components/audio-controls.tsx index b45d3c1..deb351f 100644 --- a/src/components/sticky-components/audio-controls.tsx +++ b/src/components/sticky-components/audio-controls.tsx @@ -16,12 +16,17 @@ const AudioControls = () => { const [isPlaying, setIsPlaying] = useState(false); const [currentTime, setCurrentTime] = useState(0); const [duration, setDuration] = useState(1); // Default duration to 1 to prevent division by zero + const [isRtl, setIsRtl] = useState(false); const params = useParams(); const slug = params?.slug as string; // Initialize the translation hook const { t } = useTranslation("common"); - + useEffect(() => { + const storedLocale = localStorage.getItem('locale'); + const rtlLanguages = ['ar', 'ur', 'fa', 'ks', 'tg', 'bn']; + setIsRtl(rtlLanguages.includes(storedLocale ?? "")); + }, []); const play = () => { if (audioRef.current && audio) { if (lastPart && audio.audio_sync_data.length > 0) { @@ -72,6 +77,10 @@ const AudioControls = () => { function convertTo180(numerator, denominator) { if (!numerator || !denominator) return -20; // Safeguard for invalid inputs const newNumerator = (numerator * 200) / denominator; + if (isRtl) { + + return -newNumerator; // Adjust to start from -20 degrees + } return newNumerator; // Adjust to start from -20 degrees } function processSlug(slug: string): string { diff --git a/src/components/ui/range-input.tsx b/src/components/ui/range-input.tsx index d5dd447..56a334b 100644 --- a/src/components/ui/range-input.tsx +++ b/src/components/ui/range-input.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useEffect, useState } from "react"; interface RangeInputProps { value: number; @@ -6,12 +6,33 @@ interface RangeInputProps { disabled?: boolean; } -const RangeInput: React.FC = ({ value, onChange, disabled = false }) => { +const RangeInput: React.FC = ({ + value, + onChange, + disabled = false, +}) => { + // State for detecting RTL + const [isRtl, setIsRtl] = useState(false); + + useEffect(() => { + // Check language from localStorage + const storedLocale = localStorage.getItem("locale"); + // Define RTL languages + const rtlLanguages = ["ar", "ur", "fa", "ks", "tg", "bn"]; + // Set RTL state if the stored locale is in the RTL languages + if (storedLocale && rtlLanguages.includes(storedLocale)) { + setIsRtl(true); + } else { + setIsRtl(false); + } + }, []); const handleChange = (event: React.ChangeEvent) => { onChange(Number(event.target.value)); }; + // Calculate the normalized value for RTL languages + return (
= ({ value, onChange, disabled = fal disabled={disabled} className={`w-28 h-[2px] outline-none transition-opacity duration-150 ease-in-out mr-3`} style={{ - appearance: 'none', + appearance: "none", opacity: disabled ? 0.5 : 1, - background: `linear-gradient(to right, #F4846F ${(value - 80) / 1.2}%, #EBEBEB ${(value - 80) / 1.2}%)`, + background: isRtl + ? `linear-gradient(to left, #F4846F ${ (value - 80) / 1.2 }%, #EBEBEB ${(value - 80) / 1.2}%)` + : `linear-gradient(to right, #F4846F ${(value - 80) / 1.2}%, #EBEBEB ${(value - 80) / 1.2}%)`, }} /> {value}%