Compare commits

...
Author SHA1 Message Date
Majdalkilany0 52fb5f3984 Merge pull request #91 from Zod-Alkhair/feature/help-support-faq-lookup
fix build error
2026-01-25 14:13:14 +03:00
Abdalhamid Alhamad db946b9531 fix build error 2026-01-25 14:10:46 +03:00
Majdalkilany0 d34508dca9 Merge pull request #90 from Zod-Alkhair/feature/help-support-faq-lookup
feat(lookup): add localized help/support FAQs
2026-01-25 13:16:36 +03:00
Abdalhamid Alhamad 25ede3c9e7 feat(lookup): add localized help/support FAQs 2026-01-25 13:15:59 +03:00
Majdalkilany0 47b825c4b2 Merge pull request #89 from Zod-Alkhair/feature/notification-system-fcm-registration
feat: enhance card service and transaction notification for shared ac…
2026-01-20 16:28:42 +03:00
Majdalkilany0 6a250efd5e Merge pull request #88 from Zod-Alkhair/feature/notification-system-fcm-registration
feat: enhance transaction notification listener for internal transfer…
2026-01-20 15:21:45 +03:00
Majdalkilany0 604cb7ce25 Merge pull request #87 from Zod-Alkhair/feature/notification-system-fcm-registration
fix the messages
2026-01-20 14:42:03 +03:00
Majdalkilany0 ef5572440c Merge pull request #86 from Zod-Alkhair/fix/spending-history-junior-id-query
fix: correct junior ID to customer ID mapping in transaction queries
2026-01-20 12:50:34 +03:00
Abdalhamid Alhamad 64623c7cea fix: correct junior ID to customer ID mapping in transaction queries
Fixed spending history and related transaction queries that were incorrectly
using juniorId as customerId. The queries now properly join through the
Customer -> Junior relationship to filter by junior ID.

Affected methods:
- getTransactionsForCardWithinDateRange (spending history)
- findTransfersToJunior (transfers list)
- countTransfersToJunior (transfers count)
- findTransactionById (transaction details)

This fixes the spending history endpoint which was returning empty results
due to ID mismatch between Junior entity ID and Customer entity ID.

Performance impact: Minimal (~1-2ms overhead from additional joins on
indexed foreign keys). The queries now return correct results instead of
0 results.
2026-01-20 12:39:10 +03:00
Majdalkilany0 4ca8123a67 Merge pull request #85 from Zod-Alkhair/feature/notification-system-fcm-registration
feat: refine transaction notification listener for improved balance c…
2026-01-14 16:57:36 +03:00
Majdalkilany0 e734060c52 Merge pull request #84 from Zod-Alkhair/feature/notification-system-fcm-registration
feat: improve transaction notification listener for accurate balance …
2026-01-14 16:33:05 +03:00
Majdalkilany0 5e6c8d96de Merge pull request #83 from Zod-Alkhair/feature/notification-system-fcm-registration
feat: add timezone support to user and device entities
2026-01-14 16:12:59 +03:00
Majdalkilany0 0f56381703 Merge pull request #82 from Zod-Alkhair/feature/notification-system-fcm-registration
feat: enhance card and transaction services for balance updates
2026-01-14 14:52:57 +03:00
Majdalkilany0 887bd20217 Merge pull request #81 from Zod-Alkhair/feature/notification-system-fcm-registration
feat: enhance card service validation and notification integration
2026-01-14 13:27:56 +03:00
Majdalkilany0 2e21acac7f Merge pull request #80 from Zod-Alkhair/feature/notification-system-fcm-registration
feat: implement KYC and card notification events
2026-01-14 12:57:11 +03:00
Majdalkilany0 652359b1bf Merge pull request #79 from Zod-Alkhair/feature/notification-system-fcm-registration
feat: enhance transaction notification logging and error handling
2026-01-12 16:48:13 +03:00
Majdalkilany0 2d6524be9f Merge pull request #78 from Zod-Alkhair/feature/notification-system-fcm-registration
refactor: standardize notification message formatting
2026-01-12 16:30:32 +03:00
Majdalkilany0 3ab00dfc29 Merge pull request #76 from Zod-Alkhair/feature/notification-system-fcm-registration
feat: implement money request notification system
2026-01-12 16:15:19 +03:00
Majdalkilany0 11b2b25adc Merge pull request #75 from Zod-Alkhair/feature/notification-system-fcm-registration
feat: enhance Redis module exports for pub/sub functionality
2026-01-11 14:40:12 +03:00
Majdalkilany0 ed8cf4b4f8 Merge pull request #74 from Zod-Alkhair/feature/notification-system-fcm-registration
Feature/notification system fcm registration
2026-01-11 14:31:58 +03:00
Majdalkilany0 98f6aaf01f Merge pull request #73 from Zod-Alkhair/feature/notification-system-fcm-registration
add eveint lestiner to the parent
2026-01-06 14:52:52 +03:00
Majdalkilany0 16f8756b74 Merge pull request #72 from Zod-Alkhair/feature/notification-system-fcm-registration
merge conflect
2026-01-06 12:58:49 +03:00
Majdalkilany0 f849003142 Merge pull request #71 from Zod-Alkhair/feature/notification-system-fcm-registration
Feature/notification system fcm registration
2026-01-06 12:54:45 +03:00
8 changed files with 148 additions and 6 deletions
@@ -92,7 +92,9 @@ export class TransactionRepository {
return this.transactionRepository
.createQueryBuilder('transaction')
.innerJoinAndSelect('transaction.card', 'card')
.where('card.customerId = :juniorId', { juniorId })
.innerJoin('card.customer', 'customer')
.innerJoin('customer.junior', 'junior')
.where('junior.id = :juniorId', { juniorId })
.andWhere('transaction.transactionScope = :scope', { scope: TransactionScope.CARD })
.andWhere('transaction.transactionType = :type', { type: TransactionType.EXTERNAL })
.andWhere('transaction.transactionDate BETWEEN :startDate AND :endDate', { startDate, endDate })
@@ -153,7 +155,9 @@ export class TransactionRepository {
.createQueryBuilder('tx')
.innerJoinAndSelect('tx.card', 'card')
.innerJoinAndSelect('card.account', 'account')
.where('card.customerId = :juniorId', { juniorId })
.innerJoin('card.customer', 'customer')
.innerJoin('customer.junior', 'junior')
.where('junior.id = :juniorId', { juniorId })
.andWhere('tx.transactionScope = :scope', { scope: TransactionScope.CARD })
.andWhere('tx.transactionType = :type', { type: TransactionType.INTERNAL })
.orderBy('tx.transactionDate', 'DESC')
@@ -166,7 +170,9 @@ export class TransactionRepository {
return this.transactionRepository
.createQueryBuilder('tx')
.innerJoin('tx.card', 'card')
.where('card.customerId = :juniorId', { juniorId })
.innerJoin('card.customer', 'customer')
.innerJoin('customer.junior', 'junior')
.where('junior.id = :juniorId', { juniorId })
.andWhere('tx.transactionScope = :scope', { scope: TransactionScope.CARD })
.andWhere('tx.transactionType = :type', { type: TransactionType.INTERNAL })
.getCount();
@@ -176,8 +182,10 @@ export class TransactionRepository {
return this.transactionRepository
.createQueryBuilder('tx')
.innerJoinAndSelect('tx.card', 'card')
.innerJoin('card.customer', 'customer')
.innerJoin('customer.junior', 'junior')
.where('tx.id = :transactionId', { transactionId })
.andWhere('card.customerId = :juniorId', { juniorId })
.andWhere('junior.id = :juniorId', { juniorId })
.getOne();
}
}
@@ -1,9 +1,12 @@
import { Controller, Get, UseGuards } from '@nestjs/common';
import { BadRequestException, Controller, Get, Req, UseGuards } from '@nestjs/common';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import { Request } from 'express';
import { AccessTokenGuard } from '~/common/guards';
import { ApiDataArrayResponse } from '~/core/decorators';
import { ApiDataArrayResponse, ApiLangRequestHeader } from '~/core/decorators';
import { ResponseFactory } from '~/core/utils';
import { DocumentMetaResponseDto } from '~/document/dtos/response';
import { HelpSupportFaqResponseDto } from '../dtos/response';
import { LookupLanguage } from '../enums';
import { LookupService } from '../services';
@Controller('lookup')
@@ -29,4 +32,24 @@ export class LookupController {
return ResponseFactory.dataArray(avatars.map((avatar) => new DocumentMetaResponseDto(avatar)));
}
@UseGuards(AccessTokenGuard)
@Get('help-support-faqs')
@ApiDataArrayResponse(HelpSupportFaqResponseDto)
@ApiLangRequestHeader()
getHelpSupportFaqs(@Req() request: Request) {
const header = request.headers['accept-language'];
const lang = Array.isArray(header) ? header[0] : header;
const normalized = (lang || '').trim().toLowerCase();
if (normalized && normalized !== LookupLanguage.EN && normalized !== LookupLanguage.AR) {
throw new BadRequestException('Accept-Language must be "en" or "ar".');
}
const faqs = this.lookupService.getHelpSupportFaqs(
normalized === LookupLanguage.AR ? LookupLanguage.AR : LookupLanguage.EN,
);
return ResponseFactory.dataArray(faqs);
}
}
@@ -0,0 +1,72 @@
[
{
"id": "transfer_failed_or_delayed",
"question_en": "What happens if a transfer fails or is delayed?",
"answer_en": "If a transfer fails, the amount will not be deducted from your balance. If a transfer is delayed, it will usually complete within a short time. If the issue continues, please contact customer support.",
"question_ar": "ماذا يحدث إذا فشل التحويل أو تأخر؟",
"answer_ar": "إذا فشل التحويل، لن يُخصم المبلغ من رصيدك. إذا تأخر التحويل، فعادةً يكتمل خلال وقت قصير. إذا استمرت المشكلة، يرجى التواصل مع دعم العملاء."
},
{
"id": "same_email_or_phone_multiple_accounts",
"question_en": "Can I use the same email or phone number for multiple accounts?",
"answer_en": "No. Each email address and phone number can be used for only one account.",
"question_ar": "هل يمكنني استخدام نفس البريد الإلكتروني أو رقم الهاتف لعدة حسابات؟",
"answer_ar": "لا. يمكن استخدام كل بريد إلكتروني ورقم هاتف لحساب واحد فقط."
},
{
"id": "update_profile_details",
"question_en": "How do I update my profile details?",
"answer_en": "Go to Profile - Edit Profile, update your details, and save the changes.",
"question_ar": "كيف يمكنني تحديث بيانات ملفي الشخصي؟",
"answer_ar": "انتقل إلى الملف الشخصي - تعديل الملف الشخصي، حدّث بياناتك ثم احفظ التغييرات."
},
{
"id": "change_email_address",
"question_en": "How do I change my email address?",
"answer_en": "You can update your email or phone number from Profile - Edit Profile. You may be asked to re-login for security reasons.",
"question_ar": "كيف أغيّر عنوان بريدي الإلكتروني؟",
"answer_ar": "يمكنك تحديث بريدك الإلكتروني أو رقم هاتفك من الملف الشخصي - تعديل الملف الشخصي. قد يُطلب منك تسجيل الدخول مرة أخرى لأسباب أمنية."
},
{
"id": "change_phone_number",
"question_en": "How do I change my phone number?",
"answer_en": "You cannot update your phone number",
"question_ar": "كيف أغيّر رقم هاتفي؟",
"answer_ar": "لا يمكنك تحديث رقم هاتفك."
},
{
"id": "activate_card",
"question_en": "How do I activate my card?",
"answer_en": "Transfer 20 SAR to activate your card. Once completed, your card will become active.",
"question_ar": "كيف أقوم بتفعيل بطاقتي؟",
"answer_ar": "حوّل 20 ريالًا سعوديًا لتفعيل بطاقتك. بعد إتمام التحويل، ستصبح البطاقة نشطة."
},
{
"id": "why_transfer_20_sar",
"question_en": "Why do I need to transfer 20 SAR to activate the card?",
"answer_en": "This amount is required to activate the card and enable usage.",
"question_ar": "لماذا يجب علي تحويل 20 ريالًا سعوديًا لتفعيل البطاقة؟",
"answer_ar": "هذا المبلغ مطلوب لتفعيل البطاقة وتمكين استخدامها."
},
{
"id": "where_activation_amount_go",
"question_en": "Where does the activation amount go?",
"answer_en": "The activation amount is collected by the company as part of the card activation process.",
"question_ar": "أين يذهب مبلغ التفعيل؟",
"answer_ar": "يتم تحصيل مبلغ التفعيل من قبل الشركة كجزء من عملية تفعيل البطاقة."
},
{
"id": "top_up_external_bank",
"question_en": "Can I top up from an external bank account?",
"answer_en": "Yes. You can transfer funds from your external bank to your ZOD account",
"question_ar": "هل يمكنني الشحن من حساب بنكي خارجي؟",
"answer_ar": "نعم. يمكنك تحويل الأموال من بنكك الخارجي إلى حسابك في زد."
},
{
"id": "data_security",
"question_en": "Is my data secure in the ZOD app?",
"answer_en": "Yes. We use secure systems and encryption to protect your data.",
"question_ar": "هل بياناتي آمنة في تطبيق زد؟",
"answer_ar": "نعم. نستخدم أنظمة آمنة وتشفيرًا لحماية بياناتك."
}
]
@@ -0,0 +1,18 @@
import { ApiProperty } from '@nestjs/swagger';
export class HelpSupportFaqResponseDto {
@ApiProperty()
id!: string;
@ApiProperty()
question!: string;
@ApiProperty()
answer!: string;
constructor(item: { id: string; question: string; answer: string }) {
this.id = item.id;
this.question = item.question;
this.answer = item.answer;
}
}
@@ -0,0 +1 @@
export * from './help-support-faq.response.dto';
+1
View File
@@ -0,0 +1 @@
export * from './lookup-language.enum';
@@ -0,0 +1,4 @@
export enum LookupLanguage {
EN = 'en',
AR = 'ar',
}
@@ -1,6 +1,9 @@
import { Injectable, Logger } from '@nestjs/common';
import { DocumentType } from '~/document/enums';
import { DocumentService, OciService } from '~/document/services';
import { HelpSupportFaqResponseDto } from '../dtos/response';
import { LookupLanguage } from '../enums';
import helpSupportFaqs from '../data/help-support-faqs.json';
@Injectable()
export class LookupService {
@@ -33,4 +36,16 @@ export class LookupService {
this.logger.log(`Default tasks logos returned successfully`);
return documents;
}
getHelpSupportFaqs(lang: LookupLanguage = LookupLanguage.EN): HelpSupportFaqResponseDto[] {
const useArabic = lang === LookupLanguage.AR;
return helpSupportFaqs.map((faq) =>
new HelpSupportFaqResponseDto({
id: faq.id,
question: useArabic ? faq.question_ar : faq.question_en,
answer: useArabic ? faq.answer_ar : faq.answer_en,
}),
);
}
}