From f82e8c17abadd23729e1c25108b1f3000dd96f6b Mon Sep 17 00:00:00 2001 From: iqbalpa Date: Sun, 21 Jul 2024 19:50:50 +0700 Subject: [PATCH 1/4] feat: create dialog for tafsir --- package.json | 2 + src/api/api.tsx | 13 ++- src/components/sidebar/sidebar.tsx | 1 - src/components/ui/alert-dialog.tsx | 141 ++++++++++++++++++++++++ src/components/ui/button.tsx | 56 ++++++++++ src/constant/surah.constant.ts | 5 + src/modules/detailSurah/detailSurah.tsx | 52 +++++++-- yarn.lock | 16 ++- 8 files changed, 270 insertions(+), 16 deletions(-) create mode 100644 src/components/ui/alert-dialog.tsx create mode 100644 src/components/ui/button.tsx diff --git a/package.json b/package.json index 1ff76e3..af677b0 100644 --- a/package.json +++ b/package.json @@ -12,8 +12,10 @@ "format:fix": "prettier --write --list-different ." }, "dependencies": { + "@radix-ui/react-alert-dialog": "^1.1.1", "@radix-ui/react-dialog": "^1.1.1", "@radix-ui/react-scroll-area": "^1.1.0", + "@radix-ui/react-slot": "^1.1.0", "axios": "^1.7.2", "class-variance-authority": "^0.7.0", "clsx": "^2.1.1", diff --git a/src/api/api.tsx b/src/api/api.tsx index de1f912..85ec5e6 100644 --- a/src/api/api.tsx +++ b/src/api/api.tsx @@ -1,5 +1,5 @@ import axios from 'axios'; -import { DetailSurah, ISurah } from '@/constant/surah.constant'; +import { DetailSurah, ISurah, Tafsir } from '@/constant/surah.constant'; const BASE_URL = 'https://equran.id'; @@ -24,3 +24,14 @@ export const getSurahByNomor = async (nomor: number): Promise => { const surah: DetailSurah = res.data.data; return surah; }; + +export const getTafsirByNomor = async (nomor: number): Promise => { + const res = await axios.get(`${BASE_URL}/api/v2/tafsir/${nomor}`, { + headers: { + Accept: '*/*', + 'Content-Type': 'application/json', + }, + }); + const tafsir: Tafsir[] = res.data.data.tafsir; + return tafsir; +}; diff --git a/src/components/sidebar/sidebar.tsx b/src/components/sidebar/sidebar.tsx index eff7064..3196fbf 100644 --- a/src/components/sidebar/sidebar.tsx +++ b/src/components/sidebar/sidebar.tsx @@ -15,7 +15,6 @@ const Sidebar: React.FC = () => { const fetchData = async () => { try { const res = await getAllSurah(); - console.log(res); setSurahs(res); } catch (e) { console.log('failed to fetch the surah'); diff --git a/src/components/ui/alert-dialog.tsx b/src/components/ui/alert-dialog.tsx new file mode 100644 index 0000000..fa9b155 --- /dev/null +++ b/src/components/ui/alert-dialog.tsx @@ -0,0 +1,141 @@ +'use client'; + +import * as React from 'react'; +import * as AlertDialogPrimitive from '@radix-ui/react-alert-dialog'; + +import { cn } from '@/lib/utils'; +import { buttonVariants } from '@/components/ui/button'; + +const AlertDialog = AlertDialogPrimitive.Root; + +const AlertDialogTrigger = AlertDialogPrimitive.Trigger; + +const AlertDialogPortal = AlertDialogPrimitive.Portal; + +const AlertDialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName; + +const AlertDialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + +)); +AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName; + +const AlertDialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +AlertDialogHeader.displayName = 'AlertDialogHeader'; + +const AlertDialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +AlertDialogFooter.displayName = 'AlertDialogFooter'; + +const AlertDialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName; + +const AlertDialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogDescription.displayName = + AlertDialogPrimitive.Description.displayName; + +const AlertDialogAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName; + +const AlertDialogCancel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName; + +export { + AlertDialog, + AlertDialogPortal, + AlertDialogOverlay, + AlertDialogTrigger, + AlertDialogContent, + AlertDialogHeader, + AlertDialogFooter, + AlertDialogTitle, + AlertDialogDescription, + AlertDialogAction, + AlertDialogCancel, +}; diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx new file mode 100644 index 0000000..0ba4277 --- /dev/null +++ b/src/components/ui/button.tsx @@ -0,0 +1,56 @@ +import * as React from "react" +import { Slot } from "@radix-ui/react-slot" +import { cva, type VariantProps } from "class-variance-authority" + +import { cn } from "@/lib/utils" + +const buttonVariants = cva( + "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-destructive-foreground hover:bg-destructive/90", + outline: + "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: "hover:bg-accent hover:text-accent-foreground", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-10 px-4 py-2", + sm: "h-9 rounded-md px-3", + lg: "h-11 rounded-md px-8", + icon: "h-10 w-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + } +) + +export interface ButtonProps + extends React.ButtonHTMLAttributes, + VariantProps { + asChild?: boolean +} + +const Button = React.forwardRef( + ({ className, variant, size, asChild = false, ...props }, ref) => { + const Comp = asChild ? Slot : "button" + return ( + + ) + } +) +Button.displayName = "Button" + +export { Button, buttonVariants } diff --git a/src/constant/surah.constant.ts b/src/constant/surah.constant.ts index d82ea7e..be5eb4e 100644 --- a/src/constant/surah.constant.ts +++ b/src/constant/surah.constant.ts @@ -37,3 +37,8 @@ interface BriefSurah { namaLatin: string; nomor: number; } + +export interface Tafsir { + ayat: number; + teks: string; +} diff --git a/src/modules/detailSurah/detailSurah.tsx b/src/modules/detailSurah/detailSurah.tsx index e82ab01..e85989c 100644 --- a/src/modules/detailSurah/detailSurah.tsx +++ b/src/modules/detailSurah/detailSurah.tsx @@ -1,23 +1,37 @@ 'use client'; -import { getSurahByNomor } from '@/api/api'; +import { getSurahByNomor, getTafsirByNomor } from '@/api/api'; import { ScrollArea } from '@/components/ui/scroll-area'; -import { DetailSurah } from '@/constant/surah.constant'; -import { Play } from 'lucide-react'; +import { DetailSurah, Tafsir } from '@/constant/surah.constant'; +import { BookOpen, Play } from 'lucide-react'; import { usePathname } from 'next/navigation'; import React, { useEffect, useState } from 'react'; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from '@/components/ui/alert-dialog'; + const DetailSurahPage: React.FC = () => { const pathname = usePathname(); const nomorSurah = pathname.split('/')[1]; const [surah, setSurah] = useState(); + const [tafsir, setTafsir] = useState([]); useEffect(() => { const fetchSurah = async () => { try { const res = await getSurahByNomor(parseInt(nomorSurah)); - console.log(res); setSurah(res); + const res2 = await getTafsirByNomor(parseInt(nomorSurah)); + setTafsir(res2); } catch (e) { console.log(`failed to fetch surah no ${nomorSurah}`); } @@ -25,7 +39,7 @@ const DetailSurahPage: React.FC = () => { fetchSurah(); }, [pathname]); - if (!surah) { + if (!surah || !tafsir) { return null; } @@ -47,15 +61,29 @@ const DetailSurahPage: React.FC = () => {

{surah.nomor}:{ayat.nomorAyat}

- + + + + + + + + Tafsir {surah.namaLatin} Ayat {ayat.nomorAyat} + + + + + {tafsir[ayat.nomorAyat]?.teks} + + + + Tutup + + +

diff --git a/yarn.lock b/yarn.lock index 07d195a..61f99a3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -200,6 +200,18 @@ resolved "https://registry.yarnpkg.com/@radix-ui/primitive/-/primitive-1.1.0.tgz#42ef83b3b56dccad5d703ae8c42919a68798bbe2" integrity sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA== +"@radix-ui/react-alert-dialog@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.1.tgz#f49c987b9e4f2bf37005b3864933e2b3beac907a" + integrity sha512-wmCoJwj7byuVuiLKqDLlX7ClSUU0vd9sdCeM+2Ls+uf13+cpSJoMgwysHq1SGVVkJj5Xn0XWi1NoRCdkMpr6Mw== + dependencies: + "@radix-ui/primitive" "1.1.0" + "@radix-ui/react-compose-refs" "1.1.0" + "@radix-ui/react-context" "1.1.0" + "@radix-ui/react-dialog" "1.1.1" + "@radix-ui/react-primitive" "2.0.0" + "@radix-ui/react-slot" "1.1.0" + "@radix-ui/react-compose-refs@1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz#656432461fc8283d7b591dcf0d79152fae9ecc74" @@ -210,7 +222,7 @@ resolved "https://registry.yarnpkg.com/@radix-ui/react-context/-/react-context-1.1.0.tgz#6df8d983546cfd1999c8512f3a8ad85a6e7fcee8" integrity sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A== -"@radix-ui/react-dialog@^1.1.1": +"@radix-ui/react-dialog@1.1.1", "@radix-ui/react-dialog@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@radix-ui/react-dialog/-/react-dialog-1.1.1.tgz#4906507f7b4ad31e22d7dad69d9330c87c431d44" integrity sha512-zysS+iU4YP3STKNS6USvFVqI4qqx8EpiwmT5TuCApVEBca+eRCbONi4EgzfNSuVnOXvC5UPHHMjs8RXO6DH9Bg== @@ -305,7 +317,7 @@ "@radix-ui/react-use-callback-ref" "1.1.0" "@radix-ui/react-use-layout-effect" "1.1.0" -"@radix-ui/react-slot@1.1.0": +"@radix-ui/react-slot@1.1.0", "@radix-ui/react-slot@^1.1.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@radix-ui/react-slot/-/react-slot-1.1.0.tgz#7c5e48c36ef5496d97b08f1357bb26ed7c714b84" integrity sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw== From 0ae01fd1b30efb5c861078afbfb026000623794a Mon Sep 17 00:00:00 2001 From: iqbalpa Date: Sun, 21 Jul 2024 19:53:25 +0700 Subject: [PATCH 2/4] style: change tafsir button --- src/modules/detailSurah/detailSurah.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/modules/detailSurah/detailSurah.tsx b/src/modules/detailSurah/detailSurah.tsx index e85989c..d70489a 100644 --- a/src/modules/detailSurah/detailSurah.tsx +++ b/src/modules/detailSurah/detailSurah.tsx @@ -62,11 +62,13 @@ const DetailSurahPage: React.FC = () => { {surah.nomor}:{ayat.nomorAyat}

- + From ced8e4d5a4aa84d1dda29c96516bd90eaec4416c Mon Sep 17 00:00:00 2001 From: iqbalpa Date: Sun, 21 Jul 2024 19:57:52 +0700 Subject: [PATCH 3/4] refactor: create tafsir dialog component --- src/components/tafsir/tafsir.tsx | 49 +++++++++++++++++++++++++ src/modules/detailSurah/detailSurah.tsx | 42 ++++----------------- 2 files changed, 56 insertions(+), 35 deletions(-) create mode 100644 src/components/tafsir/tafsir.tsx diff --git a/src/components/tafsir/tafsir.tsx b/src/components/tafsir/tafsir.tsx new file mode 100644 index 0000000..3acf669 --- /dev/null +++ b/src/components/tafsir/tafsir.tsx @@ -0,0 +1,49 @@ +import React from 'react'; +import { + AlertDialog, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from '@/components/ui/alert-dialog'; +import { BookOpen } from 'lucide-react'; +import { ScrollArea } from '../ui/scroll-area'; + +interface ITafsirDialog { + namaSurah: string; + nomorAyat: number; + teksTafsir: string; +} + +const TasfirDialog: React.FC = ({ + namaSurah, + nomorAyat, + teksTafsir, +}) => { + return ( + + + + + + + + Tafsir {namaSurah} Ayat {nomorAyat} + + + + {teksTafsir} + + + Tutup + + + + ); +}; + +export default TasfirDialog; diff --git a/src/modules/detailSurah/detailSurah.tsx b/src/modules/detailSurah/detailSurah.tsx index d70489a..66cd3dc 100644 --- a/src/modules/detailSurah/detailSurah.tsx +++ b/src/modules/detailSurah/detailSurah.tsx @@ -1,24 +1,13 @@ 'use client'; import { getSurahByNomor, getTafsirByNomor } from '@/api/api'; +import TasfirDialog from '@/components/tafsir/tafsir'; import { ScrollArea } from '@/components/ui/scroll-area'; import { DetailSurah, Tafsir } from '@/constant/surah.constant'; -import { BookOpen, Play } from 'lucide-react'; +import { Play } from 'lucide-react'; import { usePathname } from 'next/navigation'; import React, { useEffect, useState } from 'react'; -import { - AlertDialog, - AlertDialogAction, - AlertDialogCancel, - AlertDialogContent, - AlertDialogDescription, - AlertDialogFooter, - AlertDialogHeader, - AlertDialogTitle, - AlertDialogTrigger, -} from '@/components/ui/alert-dialog'; - const DetailSurahPage: React.FC = () => { const pathname = usePathname(); const nomorSurah = pathname.split('/')[1]; @@ -64,28 +53,11 @@ const DetailSurahPage: React.FC = () => { - - - - - - - - Tafsir {surah.namaLatin} Ayat {ayat.nomorAyat} - - - - - {tafsir[ayat.nomorAyat]?.teks} - - - - Tutup - - - +

From 0ced6c8773ef4e8a9d4e1ee50d4f8a8f3c7c65b3 Mon Sep 17 00:00:00 2001 From: iqbalpa Date: Sun, 21 Jul 2024 19:59:42 +0700 Subject: [PATCH 4/4] chore: code formatting prettier --- src/components/ui/button.tsx | 52 ++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/components/ui/button.tsx b/src/components/ui/button.tsx index 0ba4277..3d70e4d 100644 --- a/src/components/ui/button.tsx +++ b/src/components/ui/button.tsx @@ -1,56 +1,56 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" +import * as React from 'react'; +import { Slot } from '@radix-ui/react-slot'; +import { cva, type VariantProps } from 'class-variance-authority'; -import { cn } from "@/lib/utils" +import { cn } from '@/lib/utils'; const buttonVariants = cva( - "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", + 'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50', { variants: { variant: { - default: "bg-primary text-primary-foreground hover:bg-primary/90", + default: 'bg-primary text-primary-foreground hover:bg-primary/90', destructive: - "bg-destructive text-destructive-foreground hover:bg-destructive/90", + 'bg-destructive text-destructive-foreground hover:bg-destructive/90', outline: - "border border-input bg-background hover:bg-accent hover:text-accent-foreground", + 'border border-input bg-background hover:bg-accent hover:text-accent-foreground', secondary: - "bg-secondary text-secondary-foreground hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", - link: "text-primary underline-offset-4 hover:underline", + 'bg-secondary text-secondary-foreground hover:bg-secondary/80', + ghost: 'hover:bg-accent hover:text-accent-foreground', + link: 'text-primary underline-offset-4 hover:underline', }, size: { - default: "h-10 px-4 py-2", - sm: "h-9 rounded-md px-3", - lg: "h-11 rounded-md px-8", - icon: "h-10 w-10", + default: 'h-10 px-4 py-2', + sm: 'h-9 rounded-md px-3', + lg: 'h-11 rounded-md px-8', + icon: 'h-10 w-10', }, }, defaultVariants: { - variant: "default", - size: "default", + variant: 'default', + size: 'default', }, - } -) + }, +); export interface ButtonProps extends React.ButtonHTMLAttributes, VariantProps { - asChild?: boolean + asChild?: boolean; } const Button = React.forwardRef( ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button" + const Comp = asChild ? Slot : 'button'; return ( - ) - } -) -Button.displayName = "Button" + ); + }, +); +Button.displayName = 'Button'; -export { Button, buttonVariants } +export { Button, buttonVariants };