diff --git a/prisma/schema.prisma b/prisma/schema.prisma
index 58f51328..e9bd392c 100644
--- a/prisma/schema.prisma
+++ b/prisma/schema.prisma
@@ -81,20 +81,20 @@ model Book {
/// [BookVersion]
versions Json[]
- /// [BookFlags]
- flags Json @default("{}")
numberOfVersions Int @default(0)
/// [BookExtraProperties]
extraProperties Json @default("{}")
+ /// [BookPhysicalDetails]
+ physicalDetails Json?
+
genres Genre[]
advancedGenres AdvancedGenre[]
author Author @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade)
authorId String
- physicalDetails String?
- coverImageUrl String?
+ coverImageUrl String?
createdAt DateTime @default(now())
updatedAt DateTime? @updatedAt
diff --git a/src/app/[locale]/t/[bookId]/_components/ai-tab/index.tsx b/src/app/[locale]/t/[bookId]/_components/ai-tab/index.tsx
index 06aa3d89..523105ce 100644
--- a/src/app/[locale]/t/[bookId]/_components/ai-tab/index.tsx
+++ b/src/app/[locale]/t/[bookId]/_components/ai-tab/index.tsx
@@ -53,14 +53,14 @@ export default function AITab({ bookSlug, bookResponse }: TabProps) {
const isLoading = isPending;
const isVersionMismatch =
- bookResponse.book.flags.aiVersion !== bookResponse.content.versionId;
+ bookResponse.book.aiVersion !== bookResponse.content.versionId;
return (
{isVersionMismatch && (
diff --git a/src/app/[locale]/t/[bookId]/_components/search-tab/index.tsx b/src/app/[locale]/t/[bookId]/_components/search-tab/index.tsx
index 18e1130a..81f63679 100644
--- a/src/app/[locale]/t/[bookId]/_components/search-tab/index.tsx
+++ b/src/app/[locale]/t/[bookId]/_components/search-tab/index.tsx
@@ -36,7 +36,7 @@ export default function SearchTab({ bookSlug, bookResponse }: TabProps) {
const { value, setValue, results, setResults } = useSearchStore();
const isVersionMismatch =
- bookResponse.book.flags.aiVersion !== bookResponse.content.versionId;
+ bookResponse.book.aiVersion !== bookResponse.content.versionId;
const { mutateAsync, isPending, error } = useMutation<
SemanticSearchBookNode[],
@@ -120,7 +120,7 @@ export default function SearchTab({ bookSlug, bookResponse }: TabProps) {
{isVersionMismatch && (
diff --git a/src/app/[locale]/t/[bookId]/_components/tab-content.tsx b/src/app/[locale]/t/[bookId]/_components/tab-content.tsx
index aeadbfe5..97a4d80c 100644
--- a/src/app/[locale]/t/[bookId]/_components/tab-content.tsx
+++ b/src/app/[locale]/t/[bookId]/_components/tab-content.tsx
@@ -10,7 +10,7 @@ export const TabContent = ({
}: TabProps & {
tabId: keyof typeof tabIdToComponent;
}) => {
- const isSupported = props.bookResponse.book.flags.aiSupported;
+ const isSupported = props.bookResponse.book.aiSupported;
if (
(props.bookResponse.content.source === "external" || !isSupported) &&
diff --git a/src/data/popular-books.ts b/src/data/popular-books.ts
index 6b153695..cfb75a3d 100644
--- a/src/data/popular-books.ts
+++ b/src/data/popular-books.ts
@@ -3,54 +3,54 @@ import { db } from "@/server/db";
import { getLocaleWhereClause } from "@/server/db/localization";
export const popularBooks = [
- { slug: "sahih" },
- { slug: "sahih-1" },
- { slug: "sunan-4" },
- { slug: "sunan-3" },
- { slug: "sahih-wa-dacif-sunan-tirmidhi" },
- { slug: "sunan-sughra" },
- { slug: "muwatta" },
- { slug: "riyad-salihin" },
- { slug: "ihya-culum-din" },
- { slug: "tafsir-jalalayn" },
- { slug: "tafsir-quran-6" },
- { slug: "fath-bari" },
+ { id: "0256Bukhari.Sahih" },
+ { id: "0261Muslim.Sahih" },
+ { id: "0275AbuDawudSijistani.Sunan" },
+ { id: "0273IbnMaja.Sunan" },
+ { id: "0303Nasai.SunanSughra" },
+ { id: "1420MuhammadNasirDinAlbani.SahihWaDacifSunanTirmidhi" },
+ { id: "0179MalikIbnAnas.Muwatta" },
+ { id: "0676Nawawi.RiyadSalihin" },
+ { id: "0505Ghazali.IhyaCulumDin" },
+ { id: "0911Suyuti.TafsirJalalayn" },
+ { id: "0774IbnKathir.TafsirQuran" },
+ { id: "0852IbnHajarCasqalani.FathBari" },
];
export const popularIslamicLawBooks = [
- { slug: "muwatta" },
- { slug: "mughni" },
- { slug: "hidaya-fi-sharh-bidaya" },
- { slug: "bidayat-mujtahid" },
- { slug: "umm" },
- { slug: "mukhtasar-4" },
- { slug: "risala" },
- { slug: "mukhtasar-sahih-bukhari" },
- { slug: "mabsut-1" },
- { slug: "radd-muhtar" },
- { slug: "muhalla-bi-athar" },
+ { id: "0179MalikIbnAnas.Muwatta" },
+ { id: "0620IbnQudamaMaqdisi.Mughni" },
+ { id: "0593BurhanDinFarghaniMarghinani.HidayaFiSharhBidaya" },
+ { id: "0595IbnRushdHafid.BidayatMujtahid" },
+ { id: "0204Shafici.Umm" },
+ { id: "0428AbuHusaynQuduri.Mukhtasar" },
+ { id: "0204Shafici.Risala" },
+ { id: "0695IbnAbiJamra.MukhtasarSahihBukhari" },
+ { id: "0483IbnAhmadSarakhsi.Mabsut" },
+ { id: "1252IbnCabidinDimashqi.RaddMuhtar" },
+ { id: "0456IbnHazm.MuhallaBiAthar" },
];
export const popularIslamicHistoryBooks = [
- { slug: "sira-nabawiyya" },
- { slug: "sira" },
- { slug: "zad-macad" },
- { slug: "bidaya-1" },
- { slug: "tarikh-5" },
- { slug: "fadail-sahaba" },
- { slug: "sira-1" },
- { slug: "wafat" },
- { slug: "jawamic-sira" },
- { slug: "qisas-anbiya-1" },
+ { id: "0213IbnHisham.SiraNabawiyya" },
+ { id: "0151IbnIshaq.Sira" },
+ { id: "0751IbnQayyimJawziyya.ZadMacad" },
+ { id: "0774IbnKathir.Bidaya" },
+ { id: "0310Tabari.Tarikh" },
+ { id: "0241IbnHanbal.FadailSahaba" },
+ { id: "0354IbnHibbanBusti.Sira" },
+ { id: "0303Nasai.Wafat" },
+ { id: "0456IbnHazm.JawamicSira" },
+ { id: "0774IbnKathir.QisasAnbiya" },
];
-const fetchBooksBySlugs = (slugs: string[], locale: PathLocale) => {
+const fetchBooksByIds = async (ids: string[], locale: PathLocale) => {
const localeWhere = getLocaleWhereClause(locale);
- return db.book.findMany({
+ const books = await db.book.findMany({
where: {
- slug: {
- in: slugs,
+ id: {
+ in: ids,
},
},
include: {
@@ -67,25 +67,32 @@ const fetchBooksBySlugs = (slugs: string[], locale: PathLocale) => {
},
},
});
+
+ // Order books by their index in the ids array to maintain specified order
+ return books.sort((a, b) => {
+ const aIndex = ids.indexOf(a.id);
+ const bIndex = ids.indexOf(b.id);
+ return aIndex - bIndex;
+ });
};
export const fetchPopularBooks = async (locale: PathLocale) => {
- return fetchBooksBySlugs(
- popularBooks.map((s) => s.slug),
+ return fetchBooksByIds(
+ popularBooks.map((s) => s.id),
locale,
);
};
export const fetchPopularIslamicLawBooks = async (locale: PathLocale) => {
- return fetchBooksBySlugs(
- popularIslamicLawBooks.map((b) => b.slug),
+ return fetchBooksByIds(
+ popularIslamicLawBooks.map((b) => b.id),
locale,
);
};
export const fetchPopularIslamicHistoryBooks = async (locale: PathLocale) => {
- return fetchBooksBySlugs(
- popularIslamicHistoryBooks.map((b) => b.slug),
+ return fetchBooksByIds(
+ popularIslamicHistoryBooks.map((b) => b.id),
locale,
);
};
diff --git a/src/lib/seo.ts b/src/lib/seo.ts
index 464f7d0e..c09bb2b0 100644
--- a/src/lib/seo.ts
+++ b/src/lib/seo.ts
@@ -72,11 +72,12 @@ export const getMetadata = async ({
...newDescription,
keywords,
authors,
+
openGraph: {
type: "website",
siteName,
url: "/",
- locale,
+ locale: locale ?? "en_US",
...newTitle,
...newDescription,
...newImages,
@@ -117,7 +118,7 @@ export const getMetadata = async ({
siteName,
url: "/",
title,
- locale,
+ locale: locale ?? "en_US",
description: description ?? defaultDescription,
images,
},
diff --git a/src/types/ApiBookResponse.ts b/src/types/ApiBookResponse.ts
index da6509aa..94aecbc6 100644
--- a/src/types/ApiBookResponse.ts
+++ b/src/types/ApiBookResponse.ts
@@ -63,9 +63,10 @@ type BookDetails = {
bio: string;
};
transliteration: string;
+ aiSupported: boolean;
+ aiVersion: string;
versions: PrismaJson.BookVersion[];
numberOfVersions: number;
- flags: PrismaJson.BookFlags;
primaryName: string;
otherNames: string[];
secondaryName?: string | null;
diff --git a/src/types/index.ts b/src/types/index.ts
index df688690..5c4589b4 100644
--- a/src/types/index.ts
+++ b/src/types/index.ts
@@ -1,30 +1,51 @@
+interface PublicationDetails {
+ investigator?: string;
+ publisher?: string;
+ publisherLocation?: string;
+ editionNumber?: string;
+ publicationYear?: number; // hijri
+}
+
+type SplitsData = { start: number; end: number }[];
+
declare global {
namespace PrismaJson {
- interface BookVersion {
- source: "openiti" | "turath" | "external" | "pdf";
+ type BookVersion = (
+ | {
+ source: "openiti" | "turath" | "external";
+ }
+ | {
+ source: "pdf";
+ ocrBookId?: string;
+ splitsData?: SplitsData;
+ }
+ ) & {
+ id: string;
value: string;
- publicationDetails?: {
- investigator?: string;
- publisher?: string;
- editionNumber?: string;
- publicationYear?: number; // hijri
- };
- }
-
- interface BookFlags {
+ publicationDetails?: PublicationDetails;
aiSupported?: boolean;
- aiVersion?: string;
- }
+ keywordSupported?: boolean;
+ };
interface AuthorExtraProperties {
_airtableReference?: string;
}
interface BookExtraProperties {
- splitsData?: { start: number; end: number }[];
_airtableReference?: string;
}
+ type BookPhysicalDetails = (
+ | {
+ type: "manuscript";
+ }
+ | ({
+ type: "published";
+ } & PublicationDetails)
+ ) & {
+ notes?: string;
+ };
+
interface GenreExtraProperties {
_airtableReference?: string;
}