1f60f1c908
- Add Course and Module models to Prisma schema - Create seed-learn.json with Daily Fiqh for Beginners (5 modules) - Create seed-learn.js with Hermes patch (strip id/courseId from create) - Add /learn page with course listing - Add /learn/[courseSlug]/[moduleId] page with content + quiz - Quiz data stored as JSON string per module - Content rendered as markdown with Key Concept, Details, Reflection, Action Step sections TODO: - Add audio player component for listen toggle - Add progress tracking per user - Add actual quiz scoring/validation - Connect to TTS pipeline for audio generation
437 lines
34 KiB
TypeScript
437 lines
34 KiB
TypeScript
/**
|
|
* NurBuddy Slash Commands
|
|
* Each command returns unique, persona-aware content.
|
|
* Uses rotation pools to ensure variety.
|
|
*/
|
|
|
|
import type { CoachPersona } from './ai'
|
|
|
|
export type SlashCommand =
|
|
| 'new' | 'fresh' | 'learn' | 'hadith' | 'quran'
|
|
| 'reminder' | 'prayer' | 'zikr' | 'history'
|
|
| 'faraid' | 'infaq' | 'help'
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// Content Pools — large enough to avoid repetition
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
const HADITH_POOL = [
|
|
{ text: 'The Prophet ﷺ said: "The best of you are those who learn the Quran and teach it." (Bukhari)', topic: 'quran', source: 'Sahih al-Bukhari' },
|
|
{ text: 'The Prophet ﷺ said: "None of you truly believes until he loves for his brother what he loves for himself." (Bukhari & Muslim)', topic: 'brotherhood', source: 'Sahih al-Bukhari & Muslim' },
|
|
{ text: 'The Prophet ﷺ said: "A man is upon the religion of his close friend, so let one of you look at whom he befriends." (Abu Dawud & Tirmidhi)', topic: 'friendship', source: 'Sunan Abu Dawud' },
|
|
{ text: 'The Prophet ﷺ said: "The strong believer is better and more beloved to Allah than the weak believer, while there is good in both." (Muslim)', topic: 'strength', source: 'Sahih Muslim' },
|
|
{ text: 'The Prophet ﷺ said: "Whoever treads a path in search of knowledge, Allah makes easy for him a path to Paradise." (Muslim)', topic: 'knowledge', source: 'Sahih Muslim' },
|
|
{ text: 'The Prophet ﷺ said: "A kind word is charity." (Bukhari)', topic: 'kindness', source: 'Sahih al-Bukhari' },
|
|
{ text: 'The Prophet ﷺ said: "The most beloved deeds to Allah are those that are consistent, even if they are small." (Bukhari & Muslim)', topic: 'consistency', source: 'Sahih al-Bukhari & Muslim' },
|
|
{ text: 'The Prophet ﷺ said: "He who believes in Allah and the Last Day, let him either speak good or remain silent." (Bukhari & Muslim)', topic: 'speech', source: 'Sahih al-Bukhari & Muslim' },
|
|
{ text: 'The Prophet ﷺ said: "The example of the believer who recites the Quran is that of a citron — it has a beautiful fragrance and a sweet taste." (Bukhari)', topic: 'quran', source: 'Sahih al-Bukhari' },
|
|
{ text: 'The Prophet ﷺ said: "Do not be envious of one another, nor inflate prices, nor hate one another, nor boycott one another. Be brothers, O servants of Allah." (Muslim)', topic: 'unity', source: 'Sahih Muslim' },
|
|
{ text: 'The Prophet ﷺ said: "Allah does not look at your outward forms and wealth, but He looks at your hearts and deeds." (Muslim)', topic: 'sincerity', source: 'Sahih Muslim' },
|
|
{ text: 'The Prophet ﷺ said: "The likeness of the one who remembers his Lord and the one who does not remember Him is like the likeness of the living and the dead." (Bukhari)', topic: 'dhikr', source: 'Sahih al-Bukhari' },
|
|
{ text: 'The Prophet ﷺ said: "The one who looks after a widow or a poor person is like a mujahid in the path of Allah." (Bukhari & Muslim)', topic: 'charity', source: 'Sahih al-Bukhari & Muslim' },
|
|
{ text: 'The Prophet ﷺ said: "If anyone relieves a Muslim of a burden from the burdens of the world, Allah will relieve him of a burden from the burdens of the Day of Resurrection." (Muslim)', topic: 'helping', source: 'Sahih Muslim' },
|
|
{ text: 'The Prophet ﷺ said: "There is a polish for everything that takes away rust, and the polish for the heart is the remembrance of Allah." (Bukhari)', topic: 'dhikr', source: 'Sahih al-Bukhari' },
|
|
{ text: 'The Prophet ﷺ said: "The most complete of believers in iman are those with the best character." (Tirmidhi)', topic: 'character', source: 'Jami at-Tirmidhi' },
|
|
{ text: 'The Prophet ﷺ said: "If the Final Hour comes while you have a palm seedling in your hand, plant it if you can." (Ahmad)', topic: 'hope', source: 'Musnad Ahmad' },
|
|
{ text: 'The Prophet ﷺ said: "Take advantage of five before five: your youth before your old age, your health before your sickness, your wealth before your poverty, your free time before your busyness, and your life before your death." (Hakim)', topic: 'time', source: 'Mustadrak al-Hakim' },
|
|
{ text: 'The Prophet ﷺ said: "Verily, Allah has angels who roam the roads seeking out the people of dhikr." (Bukhari)', topic: 'dhikr', source: 'Sahih al-Bukhari' },
|
|
{ text: 'The Prophet ﷺ said: "The one who guides to good is like the one who does it." (Tirmidhi)', topic: 'guidance', source: 'Jami at-Tirmidhi' },
|
|
{ text: 'The Prophet ﷺ said: "Part of the perfection of one\'s Islam is leaving aside what does not concern him." (Tirmidhi)', topic: 'focus', source: 'Jami at-Tirmidhi' },
|
|
{ text: 'The Prophet ﷺ said: "The closest of people to me on the Day of Judgment are those with the best character." (Tirmidhi)', topic: 'character', source: 'Jami at-Tirmidhi' },
|
|
{ text: 'The Prophet ﷺ said: "When a person dies, his deeds come to an end except three: ongoing charity, beneficial knowledge, or a righteous child who prays for him." (Muslim)', topic: 'legacy', source: 'Sahih Muslim' },
|
|
{ text: 'The Prophet ﷺ said: "The believer who mixes with people and bears their harm with patience is better than the believer who does not mix with people and does not bear their harm." (Tirmidhi)', topic: 'patience', source: 'Jami at-Tirmidhi' },
|
|
{ text: 'The Prophet ﷺ said: "Whoever makes the Hereafter his goal, Allah places his richness in his heart, gathers his affairs, and the world comes to him willingly." (Ibn Majah)', topic: 'hereafter', source: 'Sunan Ibn Majah' },
|
|
]
|
|
|
|
const QURAN_POOL = [
|
|
{ ayah: 'And He found you lost and guided [you]. [93:7]', surah: 'Ad-Duha', context: 'No matter how lost you feel, Allah has already guided you to this moment. Trust the path.' },
|
|
{ ayah: 'So verily, with every difficulty, there is relief. Verily, with every difficulty, there is relief. [94:5-6]', surah: 'Ash-Sharh', context: 'Allah repeats it twice to assure you — relief is guaranteed. Hold on.' },
|
|
{ ayah: 'And your Lord says, "Call upon Me; I will respond to you." [40:60]', surah: 'Ghafir', context: 'Every dua you\'ve made has been heard. The response may be delayed, but it is never denied.' },
|
|
{ ayah: 'Allah does not burden a soul beyond that it can bear. [2:286]', surah: 'Al-Baqarah', context: 'Whatever you\'re facing right now — you were built for it. Allah trusts your strength.' },
|
|
{ ayah: 'And He is with you wherever you are. [57:4]', surah: 'Al-Hadid', context: 'In the darkest room, in the loneliest hour — He is there. You are never alone.' },
|
|
{ ayah: 'Say, "O My servants who have transgressed against themselves, do not despair of the mercy of Allah." [39:53]', surah: 'Az-Zumar', context: 'The door of tawbah is wide open. Walk through it. He is waiting.' },
|
|
{ ayah: 'Indeed, Allah will not change the condition of a people until they change what is in themselves. [13:11]', surah: 'Ar-Ra\'d', context: 'Change begins inside. One small step today is a revolution of the soul.' },
|
|
{ ayah: 'And We have certainly made the Quran easy for remembrance, so is there any who will remember? [54:17]', surah: 'Al-Qamar', context: 'The Quran was designed for YOU to understand. Not scholars alone. You.' },
|
|
{ ayah: 'Indeed, the patient will be given their reward without account. [39:10]', surah: 'Az-Zumar', context: 'Every tear, every sleepless night, every silent struggle — it all counts. In full.' },
|
|
{ ayah: 'No soul knows what has been hidden for them of comfort for the eyes as reward for what they used to do. [32:17]', surah: 'As-Sajda', context: 'Paradise is more beautiful than anything you can imagine. Keep going.' },
|
|
{ ayah: 'And whoever fears Allah — He will make for him a way out. [65:2]', surah: 'At-Talaq', context: 'Whatever dead-end you\'re facing, taqwa opens doors you didn\'t know existed.' },
|
|
{ ayah: 'For indeed, with hardship [will be] ease. [94:5]', surah: 'Ash-Sharh', context: 'Ease is not just coming — it is already written, paired with your hardship.' },
|
|
{ ayah: 'And seek help through patience and prayer. [2:45]', surah: 'Al-Baqarah', context: 'When nothing else works, salah and sabr always do. They are your anchors.' },
|
|
{ ayah: 'Indeed, my Lord is near and responsive. [11:61]', surah: 'Hud', context: 'He is not distant. He is not busy. He is near, and He answers.' },
|
|
{ ayah: 'And We have not sent you except as a mercy to the worlds. [21:107]', surah: 'Al-Anbiya', context: 'The Prophet ﷺ was mercy embodied. His sunnah is a map back to gentleness.' },
|
|
{ ayah: 'Indeed, Allah is with the patient. [2:153]', surah: 'Al-Baqarah', context: 'Patience is not passive waiting. It is active trust. And Allah stands with the patient.' },
|
|
{ ayah: 'And whoever relies upon Allah — then He is sufficient for him. [65:3]', surah: 'At-Talaq', context: 'Let go of the illusion of control. Tawakkul is freedom.' },
|
|
{ ayah: 'Do not lose hope in the mercy of Allah. [12:87]', surah: 'Yusuf', context: 'Ya\'qub lost his sight crying for Yusuf, yet he said this. Your storm will pass too.' },
|
|
{ ayah: 'And the Hereafter is better for you than the first [life]. [93:4]', surah: 'Ad-Duha', context: 'Whatever you missed here, whatever hurt you — the next life is better. Infinitely.' },
|
|
{ ayah: 'And you do not will except that Allah wills. [76:30]', surah: 'Al-Insan', context: 'Even your desire to change, to grow, to return to Him — that is His gift to you.' },
|
|
{ ayah: 'Indeed, in the remembrance of Allah do hearts find rest. [13:28]', surah: 'Ar-Ra\'d', context: 'Not in achievement. Not in people. Not in distraction. Only in His remembrance.' },
|
|
{ ayah: 'Say, "He is Allah, [who is] One." [112:1]', surah: 'Al-Ikhlas', context: 'Everything else is temporary. Only Allah is Eternal. Anchor your heart to the One.' },
|
|
{ ayah: 'And He is the Forgiving, the Affectionate. [85:14]', surah: 'Al-Buruj', context: 'You have not sinned a sin so big that His forgiveness cannot cover it. Return.' },
|
|
{ ayah: 'And my success is not but through Allah. [11:88]', surah: 'Hud', context: 'Every achievement, every blessing, every breath — it is all from Him. Thank Him.' },
|
|
{ ayah: 'Indeed, Allah loves those who rely [upon Him]. [3:159]', surah: 'Aal-E-Imran', context: 'Reliance on Allah is an act of love. And He loves those who love Him back.' },
|
|
]
|
|
|
|
const ZIKR_POOL = [
|
|
{ arabic: 'SubhanAllah', transliteration: 'SubhanAllah', meaning: 'Glory be to Allah', count: '33x', merit: 'A palm tree is planted for you in Paradise.' },
|
|
{ arabic: 'Alhamdulillah', transliteration: 'Alhamdulillah', meaning: 'All praise is due to Allah', count: '33x', merit: 'A palm tree is planted for you in Paradise.' },
|
|
{ arabic: 'Allahu Akbar', transliteration: 'Allahu Akbar', meaning: 'Allah is the Greatest', count: '33x', merit: 'A palm tree is planted for you in Paradise.' },
|
|
{ arabic: 'La ilaha illa Allah', transliteration: 'La ilaha illa Allah', meaning: 'There is no deity worthy of worship except Allah', count: 'As much as possible', merit: 'The best of all dhikr.' },
|
|
{ arabic: 'Astaghfirullah', transliteration: 'Astaghfirullah', meaning: 'I seek forgiveness from Allah', count: '100x daily', merit: 'Purifies the soul and opens sustenance.' },
|
|
{ arabic: 'La hawla wa la quwwata illa billah', transliteration: 'La hawla wa la quwwata illa billah', meaning: 'There is no power nor strength except through Allah', count: 'Frequently', merit: 'One of the treasures of Paradise.' },
|
|
{ arabic: 'SubhanAllahi wa bihamdihi', transliteration: 'SubhanAllahi wa bihamdihi', meaning: 'Glory be to Allah and praise be to Him', count: '100x', merit: 'Sins fall away like leaves from a tree.' },
|
|
{ arabic: 'Allahumma salli ala Muhammad', transliteration: 'Allahumma salli ala Muhammad', meaning: 'O Allah, send blessings upon Muhammad', count: '100x Friday', merit: 'The one who sends 100 salawat on Friday will have their needs fulfilled.' },
|
|
{ arabic: 'Hasbunallahu wa ni\'mal wakeel', transliteration: 'Hasbunallahu wa ni\'mal wakeel', meaning: 'Allah is sufficient for us, and He is the best Disposer of affairs', count: 'In difficulty', merit: 'Ibrahim said this when thrown in the fire.' },
|
|
{ arabic: 'Rabbana atina fid-dunya hasanah', transliteration: 'Rabbana atina fid-dunya hasanah', meaning: 'Our Lord, give us good in this world and good in the Hereafter', count: 'Frequently', merit: 'The most comprehensive dua.' },
|
|
{ arabic: 'La ilaha illa anta subhanaka inni kuntu minaz-zalimin', transliteration: 'La ilaha illa anta subhanaka inni kuntu minaz-zalimin', meaning: 'There is no god but You. Glory to You. I was among the wrongdoers', count: 'In distress', merit: 'Yunus said this in the belly of the whale. It is the dua of relief.' },
|
|
{ arabic: 'Bismillahi alladhi la yadurru ma\'asmihi shayun fil-ardi wa la fis-sama\'i', transliteration: 'Bismillahi alladhi la yadurru ma\'asmihi shayun fil-ardi wa la fis-sama\'i', meaning: 'In the name of Allah, with whose name nothing on earth or in the heavens can cause harm', count: '3x morning & evening', merit: 'Protection from all harm.' },
|
|
{ arabic: 'Raditu billahi rabban wa bil-Islami dinnan wa bi-Muhammadin rasulan', transliteration: 'Raditu billahi rabban wa bil-Islami dinnan wa bi-Muhammadin rasulan', meaning: 'I am pleased with Allah as my Lord, Islam as my religion, and Muhammad as my Messenger', count: '3x daily', merit: 'Whoever says this with certainty enters Paradise.' },
|
|
{ arabic: 'SubhanAllah wa bihamdihi, subhanAllahil azeem', transliteration: 'SubhanAllah wa bihamdihi, subhanAllahil azeem', meaning: 'Glory be to Allah and praise be to Him, glory be to Allah the Magnificent', count: 'Frequently', merit: 'Two statements are light on the tongue, heavy on the scales, beloved to the Most Merciful.' },
|
|
{ arabic: 'Ya Hayyu Ya Qayyum', transliteration: 'Ya Hayyu Ya Qayyum', meaning: 'O Ever-Living, O Self-Sustaining', count: 'In distress', merit: 'The dua of the Prophet ﷺ when distressed — calling on the names of Life and Sustenance.' },
|
|
]
|
|
|
|
const REMINDER_POOL = [
|
|
'Your body is an amanah (trust) from Allah. Treat it with care — sleep, nutrition, and movement are forms of worship.',
|
|
'The dua made between the adhan and iqamah is never rejected. Are you making the most of those moments?',
|
|
'Your parents are your door to Paradise or your door to Hell. Call them today, even if it\'s just to say "I love you."',
|
|
'You have survived 100% of your bad days. Allah has carried you through every single one. Trust Him with tomorrow.',
|
|
'The Quran was revealed in Ramadan, but its light is for every day. Open it — even one ayah — and let it speak to you.',
|
|
'Your smile to a Muslim brother is charity. Your kind word to a stranger is sadaqah. Your patience with a difficult person is jihad.',
|
|
'Night prayer (tahajjud) is when the world sleeps and the hearts of the sincere wake up. What if tonight is your night?',
|
|
'You are not defined by your worst moment. You are defined by your return to Allah. Tawbah wipes the slate clean.',
|
|
'The best investment is not in stocks or property — it is in your relationship with Allah. It yields returns in this life and the next.',
|
|
'When was the last time you cried in prayer? Not from sadness, but from the overwhelming feeling of being near your Beloved?',
|
|
'Gratitude is not just saying "Alhamdulillah." It is using every blessing to bring you closer to the One who gave it.',
|
|
'Your time is your capital. Spend it on what grows your soul, not just what grows your bank account.',
|
|
'The Prophet ﷺ taught us that the best among us are those with the best character. Are you kinder today than you were yesterday?',
|
|
'Every breath is a loan from Allah. How many breaths today did you spend in His remembrance?',
|
|
'Paradise is not cheap. It costs your desires, your ego, your attachment to this world. But the return is infinite.',
|
|
'Allah sees your private struggles. The duas you make alone, the tears you hide, the good deeds no one witnesses — He is watching, and He rewards abundantly.',
|
|
'You do not need to be perfect to start. You just need to start to become better. Every step toward Allah is a step He celebrates.',
|
|
'When you feel far from Allah, remember: it is not because He moved. It is because you stopped turning to Him. Turn back.',
|
|
'The most beloved deed to Allah is the most consistent, even if small. Do not despise the small. A river is made of drops.',
|
|
'Your struggle is your evidence of faith. Shaytan does not bother those who have already given up. The fact that you\'re fighting means Allah is with you.',
|
|
]
|
|
|
|
const FARAID_POOL = [
|
|
{ topic: 'The Six Categories of Heirs', content: 'Islamic inheritance (faraid) divides heirs into three main groups: (1) Ascendants (parents), (2) Descendants (children), and (3) Collateral relatives (siblings, uncles). Spouses are a special category. The Quran specifies exact shares in Surah An-Nisa.' },
|
|
{ topic: 'The Spouse\'s Share', content: 'A wife receives 1/4 if there are no children, and 1/8 if there are children. A husband receives 1/2 if there are no children, and 1/4 if there are children. These shares are fixed by Allah in Surah An-Nisa.' },
|
|
{ topic: 'The Daughter\'s Share', content: 'A single daughter receives 1/2. Two or more daughters share 2/3 equally. If there is a son, the daughter receives half of what the son receives (the "son gets double" principle).' },
|
|
{ topic: 'The Parents\' Share', content: 'If the deceased has children, each parent receives 1/6. If there are no children and the parents are the sole heirs, the mother receives 1/3 and the father receives 2/3 (as residuary).' },
|
|
{ topic: 'Awl and Radd', content: 'Awl (increase) happens when shares exceed 1 — the shares are proportionally reduced. Radd (return) happens when shares fall short of 1 and there are no residuary heirs — the surplus returns to existing heirs proportionally.' },
|
|
{ topic: 'The Importance of Wasiyyah', content: 'A Muslim can bequeath up to 1/3 of their estate to non-heirs or charity. The remaining 2/3 must follow the Quranic shares. Writing a will is strongly recommended in Islam.' },
|
|
{ topic: 'Grandchildren', content: 'Grandchildren generally do not inherit if their parent (the child of the deceased) is alive — this is the principle of "the closer relative excludes the more distant." However, grandchildren through a deceased son may inherit by representation in some madhabs.' },
|
|
{ topic: 'Maternal and Paternal Siblings', content: 'Full siblings (same parents) receive a share when there are no children, grandchildren, or parents. Half-siblings from the father receive half of what full siblings receive. Half-siblings from the mother have a fixed share of 1/6 when there are no children or parents.' },
|
|
]
|
|
|
|
const INFAQ_POOL = [
|
|
{ concept: 'Zakat al-Mal', detail: '2.5% of wealth held for one lunar year above the nisab threshold. It purifies your wealth and circulates blessings in the community.' },
|
|
{ concept: 'Sadaqah Jariyah', detail: 'Ongoing charity that continues to benefit after death: building a well, planting a tree, teaching knowledge, or sponsoring an orphan\'s education.' },
|
|
{ concept: 'Fidyah', detail: 'For those who cannot fast due to old age or chronic illness: feeding one poor person per missed fast. A beautiful mercy from Allah.' },
|
|
{ concept: 'Kaffarah', detail: 'Expiation for breaking an oath or other violations: fasting 3 days, feeding 10 poor people, or freeing a slave. Islam provides paths of redemption.' },
|
|
{ concept: 'The Virtue of Charity', detail: 'The Prophet ﷺ said: "Charity does not decrease wealth." Giving opens doors — rizq flows to the generous like water flows downhill.' },
|
|
{ concept: 'Feeding the Fasting', detail: 'Whoever provides iftar to a fasting person receives the same reward as the fasting person, without diminishing their reward in the slightest.' },
|
|
{ concept: 'Supporting Orphans', detail: 'The Prophet ﷺ said he and the sponsor of an orphan will be like this (holding up two fingers together) in Paradise. It is one of the highest stations.' },
|
|
{ concept: 'Riba-Free Investment', detail: 'Islamic finance prohibits interest. Instead, use profit-sharing (mudarabah), joint ventures (musharakah), or asset-backed transactions. Your wealth must grow through real value, not usury.' },
|
|
]
|
|
|
|
const PRAYER_POOL = [
|
|
{ title: 'Dua for Beginning Salah', arabic: 'Allahumma ba\'id bayni wa bayna khatayaya kama ba\'adta baynal-mashriqi wal-maghrib', meaning: 'O Allah, distance me from my sins as You have distanced the East from the West.' },
|
|
{ title: 'Dua After Wudu', arabic: 'Ashhadu an la ilaha illa Allah, wahdahu la sharika lahu, wa ashhadu anna Muhammadan abduhu wa rasuluhu', meaning: 'I bear witness that there is no god but Allah, alone without partner, and I bear witness that Muhammad is His servant and Messenger.' },
|
|
{ title: 'Dua for Laylatul Qadr', arabic: 'Allahumma innaka afuwwun tuhibbul afwa fa\'fu anni', meaning: 'O Allah, You are Pardoning and love to pardon, so pardon me.' },
|
|
{ title: 'Dua for Distress', arabic: 'La ilaha illa anta subhanaka inni kuntu minaz-zalimin', meaning: 'There is no god but You. Glory to You. I was among the wrongdoers.' },
|
|
{ title: 'Dua for Rizq', arabic: 'Allahumma arzuqni halalan tayyiban wa a\'mali bihi', meaning: 'O Allah, provide me with lawful and pure sustenance, and enable me to work with it.' },
|
|
{ title: 'Dua for Forgiveness', arabic: 'Astaghfirullah alladhi la ilaha illa huwal hayyul qayyumu wa atubu ilayh', meaning: 'I seek forgiveness from Allah, there is no god but Him, the Ever-Living, the Self-Sustaining, and I repent to Him.' },
|
|
{ title: 'Dua for Parents', arabic: 'Rabbir hamhuma kama rabbayani saghira', meaning: 'My Lord, have mercy upon them as they brought me up when I was small.' },
|
|
{ title: 'Dua for the Deceased', arabic: 'Allahumma ghfir li [name] warfa darajatahu fil-jannati waghsilhu bil-ma\'i wath-thalji wal-baradi', meaning: 'O Allah, forgive [name], raise his degree among the guided, and wash him with water, snow, and ice.' },
|
|
{ title: 'Morning Adhkar', detail: 'Say 100x: SubhanAllah wa bihamdihi. Say 100x: La ilaha illa Allah. Say 100x: Astaghfirullah. This is the daily polish for the heart.' },
|
|
{ title: 'The Best Dua', detail: 'The Prophet ﷺ was asked: "Which dua is most heard by Allah?" He said: "The dua made in the last third of the night and after the obligatory prayers."' },
|
|
]
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// Rotation helper — ensures variety
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
function pickUnique<T>(pool: T[], usedIds: Set<number>): { item: T; id: number } {
|
|
// Try to find an unused item
|
|
const unused = pool.map((item, i) => ({ item, id: i })).filter(({ id }) => !usedIds.has(id))
|
|
|
|
if (unused.length === 0) {
|
|
// All used — reset and pick randomly
|
|
const idx = Math.floor(Math.random() * pool.length)
|
|
return { item: pool[idx], id: idx }
|
|
}
|
|
|
|
const pick = unused[Math.floor(Math.random() * unused.length)]
|
|
return pick
|
|
}
|
|
|
|
function formatResponse(text: string, persona: CoachPersona, name: string): string {
|
|
// Add persona-specific framing
|
|
const signatures: Record<CoachPersona, string> = {
|
|
nurbuddy: `\n\nWith warmth, NurBuddy`,
|
|
ghazali: `\n\nMay the light of sincerity illuminate your path — Al-Ghazali`,
|
|
ibnabbas: `\n\nWith the chain of knowledge from the Messenger of Allah ﷺ — Ibn Abbas`,
|
|
rabia: `\n\nIn the fire of love that never goes out — Rabi'a al-Adawiya`,
|
|
}
|
|
|
|
return `${text}${signatures[persona] || signatures.nurbuddy}`
|
|
}
|
|
|
|
// ─────────────────────────────────────────────────────────────
|
|
// Command Handlers
|
|
// ─────────────────────────────────────────────────────────────
|
|
|
|
export interface CommandResult {
|
|
response: string
|
|
metadata: {
|
|
command: string
|
|
summary: string
|
|
actionItems: string[]
|
|
topics: string[]
|
|
}
|
|
}
|
|
|
|
export function parseCommand(message: string): { command: SlashCommand | null; rest: string } {
|
|
const trimmed = message.trim()
|
|
if (!trimmed.startsWith('/')) return { command: null, rest: trimmed }
|
|
|
|
const parts = trimmed.slice(1).split(/\s+/, 2)
|
|
const command = parts[0].toLowerCase() as SlashCommand
|
|
const rest = parts[1] || ''
|
|
|
|
const validCommands: SlashCommand[] = [
|
|
'new', 'fresh', 'learn', 'hadith', 'quran',
|
|
'reminder', 'prayer', 'zikr', 'history',
|
|
'faraid', 'infaq', 'help',
|
|
]
|
|
|
|
if (!validCommands.includes(command)) {
|
|
return { command: null, rest: trimmed }
|
|
}
|
|
|
|
return { command, rest }
|
|
}
|
|
|
|
export function handleCommand(
|
|
command: SlashCommand,
|
|
rest: string,
|
|
persona: CoachPersona,
|
|
name: string,
|
|
seenHadith: Set<number>,
|
|
seenQuran: Set<number>,
|
|
seenZikr: Set<number>,
|
|
seenReminder: Set<number>,
|
|
seenFaraId: Set<number>,
|
|
seenInfaq: Set<number>,
|
|
seenPrayer: Set<number>,
|
|
): CommandResult {
|
|
switch (command) {
|
|
case 'new':
|
|
case 'fresh':
|
|
return {
|
|
response: formatResponse(
|
|
`A clean slate, ${name}. Every moment is a new beginning in Islam. What would you like to explore together? You can ask me anything, or use /help to see what I can do.`,
|
|
persona, name
|
|
),
|
|
metadata: { command, summary: 'Fresh start requested', actionItems: [], topics: [] },
|
|
}
|
|
|
|
case 'help':
|
|
return {
|
|
response: formatResponse(
|
|
`Here is what I can do for you, ${name}:\n\n` +
|
|
`/hadith — A random authentic hadith with context\n` +
|
|
`/quran — A Quranic verse with reflection\n` +
|
|
`/zikr — A dhikr/remembrance for your heart\n` +
|
|
`/prayer — A dua or prayer tip\n` +
|
|
`/reminder — An Islamic reminder to uplift you\n` +
|
|
`/learn — I will teach you something new about Islam\n` +
|
|
`/faraid — Learn about Islamic inheritance\n` +
|
|
`/infaq — Learn about charity and giving\n` +
|
|
`/history — See your conversation summary\n` +
|
|
`/new or /fresh — Start a fresh conversation\n` +
|
|
`/help — Show this list`,
|
|
persona, name
|
|
),
|
|
metadata: { command, summary: 'Help requested', actionItems: [], topics: ['help'] },
|
|
}
|
|
|
|
case 'hadith': {
|
|
const { item, id } = pickUnique(HADITH_POOL, seenHadith)
|
|
seenHadith.add(id)
|
|
if (seenHadith.size > HADITH_POOL.length * 0.8) seenHadith.clear() // Reset when 80% seen
|
|
|
|
let commentary = ''
|
|
if (persona === 'ghazali') {
|
|
commentary = `\n\nReflect on this, ${name}: The outward act is easy — but what is the state of your heart when you hear these words? The hadith is not merely to be memorized, but to be lived.`
|
|
} else if (persona === 'ibnabbas') {
|
|
commentary = `\n\nThis hadith is narrated in ${item.source}. The Arabic root of the key word carries layers of meaning. Would you like me to explain the linguistic depth?`
|
|
} else if (persona === 'rabia') {
|
|
commentary = `\n\nO ${name}, when the Messenger ﷺ spoke these words, he spoke from a heart that was always with Allah. Do these words find a home in your heart, or do they merely pass through your ears?`
|
|
}
|
|
|
|
return {
|
|
response: formatResponse(
|
|
`**Hadith of the Moment**\n\n${item.text}${commentary}`,
|
|
persona, name
|
|
),
|
|
metadata: { command, summary: `Hadith: ${item.topic}`, actionItems: [], topics: ['hadith', item.topic] },
|
|
}
|
|
}
|
|
|
|
case 'quran': {
|
|
const { item, id } = pickUnique(QURAN_POOL, seenQuran)
|
|
seenQuran.add(id)
|
|
if (seenQuran.size > QURAN_POOL.length * 0.8) seenQuran.clear()
|
|
|
|
let commentary = ''
|
|
if (persona === 'ghazali') {
|
|
commentary = `\n\nThe Quran has an apparent meaning and a hidden meaning, ${name}. The apparent meaning is for the mind, but the hidden meaning is for the heart. What does this ayah awaken in you?`
|
|
} else if (persona === 'ibnabbas') {
|
|
commentary = `\n\nThis verse is from Surah ${item.surah}. The context of its revelation adds profound depth. The word choices in Arabic carry meanings that translation cannot fully capture.`
|
|
} else if (persona === 'rabia') {
|
|
commentary = `\n\n${name}, the Quran is a love letter from the Beloved. This ayah was written for someone who needed to hear it — perhaps that someone is you today.`
|
|
}
|
|
|
|
return {
|
|
response: formatResponse(
|
|
`**Quranic Reflection**\n\n📖 *${item.ayah}*\n\n**From Surah ${item.surah}**\n\n${item.context}${commentary}`,
|
|
persona, name
|
|
),
|
|
metadata: { command, summary: `Quran: ${item.surah}`, actionItems: [], topics: ['quran', item.surah] },
|
|
}
|
|
}
|
|
|
|
case 'zikr': {
|
|
const { item, id } = pickUnique(ZIKR_POOL, seenZikr)
|
|
seenZikr.add(id)
|
|
if (seenZikr.size > ZIKR_POOL.length * 0.8) seenZikr.clear()
|
|
|
|
let commentary = ''
|
|
if (persona === 'rabia') {
|
|
commentary = `\n\nO ${name}, do not merely say these words with your tongue. Say them with the fire of your heart. The dhikr of the tongue without the heart is like a candle without a flame.`
|
|
} else if (persona === 'ghazali') {
|
|
commentary = `\n\nThe remembrance of Allah is the polish for the heart. But beware — the heart that remembers Allah while the tongue is busy with dunya is like a man who tries to fill a sieve with water.`
|
|
}
|
|
|
|
return {
|
|
response: formatResponse(
|
|
`**Dhikr for Your Heart**\n\n🔸 **${item.arabic}**\n\n*${item.transliteration}*\n\n**Meaning:** ${item.meaning}\n\n**Recommended:** ${item.count}\n\n**Merit:** ${item.merit}${commentary}`,
|
|
persona, name
|
|
),
|
|
metadata: { command, summary: `Dhikr: ${item.meaning}`, actionItems: [item.transliteration], topics: ['dhikr'] },
|
|
}
|
|
}
|
|
|
|
case 'reminder': {
|
|
const { item, id } = pickUnique(REMINDER_POOL, seenReminder)
|
|
seenReminder.add(id)
|
|
if (seenReminder.size > REMINDER_POOL.length * 0.8) seenReminder.clear()
|
|
|
|
return {
|
|
response: formatResponse(
|
|
`💡 **Reminder**\n\n${item}`,
|
|
persona, name
|
|
),
|
|
metadata: { command, summary: 'Reminder delivered', actionItems: [], topics: ['reminder'] },
|
|
}
|
|
}
|
|
|
|
case 'prayer': {
|
|
const { item, id } = pickUnique(PRAYER_POOL, seenPrayer)
|
|
seenPrayer.add(id)
|
|
if (seenPrayer.size > PRAYER_POOL.length * 0.8) seenPrayer.clear()
|
|
|
|
const content = 'arabic' in item
|
|
? `**${item.title}**\n\n🔸 **${(item as any).arabic}**\n\n*${(item as any).meaning}*`
|
|
: `**${item.title}**\n\n${(item as any).detail}`
|
|
|
|
return {
|
|
response: formatResponse(
|
|
`🤲 **Dua & Prayer**\n\n${content}`,
|
|
persona, name
|
|
),
|
|
metadata: { command, summary: `Dua: ${item.title}`, actionItems: ['arabic' in item ? [(item as any).arabic] : []].flat(), topics: ['dua', 'prayer'] },
|
|
}
|
|
}
|
|
|
|
case 'faraid': {
|
|
const { item, id } = pickUnique(FARAID_POOL, seenFaraId)
|
|
seenFaraId.add(id)
|
|
if (seenFaraId.size > FARAID_POOL.length * 0.8) seenFaraId.clear()
|
|
|
|
return {
|
|
response: formatResponse(
|
|
`⚖️ **Islamic Inheritance (Faraid)**\n\n**Topic:** ${item.topic}\n\n${item.content}\n\n*Note: For specific cases, consult a qualified Islamic inheritance scholar. These are general principles.*`,
|
|
persona, name
|
|
),
|
|
metadata: { command, summary: `Faraid: ${item.topic}`, actionItems: [], topics: ['faraid', 'inheritance'] },
|
|
}
|
|
}
|
|
|
|
case 'infaq': {
|
|
const { item, id } = pickUnique(INFAQ_POOL, seenInfaq)
|
|
seenInfaq.add(id)
|
|
if (seenInfaq.size > INFAQ_POOL.length * 0.8) seenInfaq.clear()
|
|
|
|
return {
|
|
response: formatResponse(
|
|
`💰 **Charity & Giving (Infaq)**\n\n**${item.concept}**\n\n${item.detail}`,
|
|
persona, name
|
|
),
|
|
metadata: { command, summary: `Infaq: ${item.concept}`, actionItems: [], topics: ['charity', 'infaq'] },
|
|
}
|
|
}
|
|
|
|
case 'learn': {
|
|
const topics = [
|
|
'the five pillars of Islam and their inner dimensions',
|
|
'the names of Allah (Asma ul-Husna) and how to live by them',
|
|
'the etiquette of seeking knowledge (adab al-ilm)',
|
|
'the concept of tawakkul (reliance on Allah) in daily life',
|
|
'the importance of intention (niyyah) in every act',
|
|
'the sunnah morning and evening adhkar',
|
|
'the meaning of ihsan (excellence in worship)',
|
|
'the signs of a sincere heart',
|
|
'the concept of qadr (divine decree) and how to accept it',
|
|
'the rights of parents in Islam',
|
|
'the etiquettes of the mosque and congregational prayer',
|
|
'the virtues of the night prayer (tahajjud)',
|
|
]
|
|
const topic = topics[Math.floor(Math.random() * topics.length)]
|
|
|
|
let prompt = ''
|
|
if (persona === 'ghazali') {
|
|
prompt = `My dear student ${name}, today let us explore ${topic}. I have written about this in my Ihya, and I wish to share with you not just the outward rules, but the inner transformation they bring.`
|
|
} else if (persona === 'ibnabbas') {
|
|
prompt = `${name}, let us turn to the Book of Allah to understand ${topic}. The Quran speaks to this directly, and the understanding of the Sahaba illuminates it further.`
|
|
} else if (persona === 'rabia') {
|
|
prompt = `O ${name}, ${topic} — this is not merely knowledge to be stored in the mind. It is love to be planted in the heart. Shall we tend to this seed together?`
|
|
} else {
|
|
prompt = `Great topic, ${name}! Let\'s learn about ${topic}. I\'ll keep it practical and relevant to your daily life.`
|
|
}
|
|
|
|
return {
|
|
response: formatResponse(prompt, persona, name),
|
|
metadata: { command, summary: `Learn: ${topic}`, actionItems: [], topics: ['learning', topic.replace(/\s+/g, '_')] },
|
|
}
|
|
}
|
|
|
|
case 'history': {
|
|
return {
|
|
response: formatResponse(
|
|
`Your conversation history is available in the "Your Commitments" section above. I remember our past sessions and use them to guide our future conversations. Keep engaging, and I will continue to learn about your journey, ${name}.`,
|
|
persona, name
|
|
),
|
|
metadata: { command, summary: 'History requested', actionItems: [], topics: ['history'] },
|
|
}
|
|
}
|
|
|
|
default:
|
|
return {
|
|
response: formatResponse(`I am not sure about that command, ${name}. Type /help to see what I can do.`, persona, name),
|
|
metadata: { command, summary: 'Unknown command', actionItems: [], topics: [] },
|
|
}
|
|
}
|
|
}
|