diff --git a/src/modules/vouching/dto/vouch.dto.ts b/src/modules/vouching/dto/vouch.dto.ts index 385a761..27ee84b 100644 --- a/src/modules/vouching/dto/vouch.dto.ts +++ b/src/modules/vouching/dto/vouch.dto.ts @@ -46,3 +46,37 @@ export class VouchResponseDto { @ApiProperty() createdAt: string; @ApiProperty() expiresAt: string; } + +export class VouchRequestItemDto { + @ApiProperty({ + description: 'Learner Stellar wallet address', + example: 'GALPHABCDEFGHIJKLMNOPQRSTUVWXYZ23456789ABCDEFGHIJKLMN', + }) + learnerWallet: string; + + @ApiProperty({ + description: 'Learner reputation score (0-100)', + example: 72, + }) + reputationScore: number; + + @ApiProperty({ + description: 'Requested loan amount in USD', + example: 500, + nullable: true, + }) + requestedLoanAmount: number | null; + + @ApiProperty({ + description: 'Loan purpose or message from the learner', + example: 'Need a loan for inventory restocking', + nullable: true, + }) + loanPurpose: string | null; + + @ApiProperty({ + description: 'ISO 8601 timestamp when the vouch was requested', + example: '2026-06-19T12:00:00.000Z', + }) + requestedAt: string; +} diff --git a/src/modules/vouching/vouching.controller.ts b/src/modules/vouching/vouching.controller.ts index 56d32ae..917caaa 100644 --- a/src/modules/vouching/vouching.controller.ts +++ b/src/modules/vouching/vouching.controller.ts @@ -18,6 +18,7 @@ import { ApproveVouchDto, RequestVouchDto, VouchResponseDto, + VouchRequestItemDto, } from './dto/vouch.dto'; import { JwtAuthGuard } from '../../common/guards/jwt-auth.guard'; import { CurrentUser } from '../../common/decorators/current-user.decorator'; @@ -72,4 +73,14 @@ export class VouchingController { ): Promise { return this.vouchingService.getMentorVouches(user.wallet); } + + @Get('requests') + @HttpCode(HttpStatus.OK) + @ApiOperation({ summary: 'Get incoming vouch requests for the authenticated mentor' }) + @ApiResponse({ status: 200, description: 'List of pending vouch requests', type: [VouchRequestItemDto] }) + async getRequests( + @CurrentUser() user: { wallet: string }, + ): Promise { + return this.vouchingService.getIncomingRequests(user.wallet); + } } diff --git a/src/modules/vouching/vouching.service.ts b/src/modules/vouching/vouching.service.ts index e39fa8c..11b41d7 100644 --- a/src/modules/vouching/vouching.service.ts +++ b/src/modules/vouching/vouching.service.ts @@ -9,6 +9,7 @@ import { ApproveVouchDto, RequestVouchDto, VouchResponseDto, + VouchRequestItemDto, VouchStatus, } from './dto/vouch.dto'; @@ -17,6 +18,7 @@ interface VouchRow { mentor_wallet: string; learner_wallet: string; message: string | null; + loan_amount: number | null; status: VouchStatus; created_at: string; expires_at: string; @@ -167,6 +169,56 @@ export class VouchingService { return rows.map((row) => this.mapToDto(row)); } + async getIncomingRequests(mentorWallet: string): Promise { + const client = this.supabaseService.getClient(); + + const { data, error } = await client + .from('vouches') + .select('learner_wallet, message, loan_amount, created_at') + .eq('mentor_wallet', mentorWallet) + .eq('status', VouchStatus.PENDING) + .order('created_at', { ascending: false }); + + if (error) { + this.logger.error(`Failed to fetch incoming requests for ${mentorWallet}: ${error.message}`); + throw new Error('Failed to fetch vouch requests.'); + } + + const rows = data ?? []; + const results: VouchRequestItemDto[] = []; + + for (const row of rows) { + const reputationScore = await this.getLearnerReputationScore(row.learner_wallet); + results.push({ + learnerWallet: row.learner_wallet, + reputationScore, + requestedLoanAmount: row.loan_amount ?? null, + loanPurpose: row.message ?? null, + requestedAt: row.created_at, + }); + } + + return results; + } + + private async getLearnerReputationScore(wallet: string): Promise { + try { + const { data, error } = await this.supabaseService.getClient() + .from('reputation_cache') + .select('score') + .eq('wallet_address', wallet) + .maybeSingle(); + + if (error || !data) { + return 0; + } + + return data.score; + } catch { + return 0; + } + } + private mapToDto(data: VouchRow): VouchResponseDto { return { id: data.id, diff --git a/supabase/migrations/20260619000001_add_vouch_request_fields.sql b/supabase/migrations/20260619000001_add_vouch_request_fields.sql new file mode 100644 index 0000000..6bf8f14 --- /dev/null +++ b/supabase/migrations/20260619000001_add_vouch_request_fields.sql @@ -0,0 +1 @@ +ALTER TABLE public.vouches ADD COLUMN loan_amount NUMERIC;