mirror of
https://git.meshkee.com/Meshkee/backend.git
synced 2026-08-12 06:40:58 +04:30
Add defaultLocale, EN names, and dashboard activity endpoints.
Expose branding.defaultLocale, optional user EN name fields, and lightweight dual daily activity for orders/customers; update project context and rules. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
4598add88c
commit
43e3912662
@@ -14,6 +14,7 @@ import { CurrentUser } from '../auth/decorators/current-user.decorator';
|
||||
import { RequireBusinessPermission } from '../auth/decorators/require-business-permission.decorator';
|
||||
import { BusinessPermissionGuard } from '../auth/guards/business-permission.guard';
|
||||
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
|
||||
import { DailyActivityQueryDto } from '../common/dto/daily-activity-query.dto';
|
||||
import { CustomersService } from './customers.service';
|
||||
import { CreateCustomerDto } from './dto/create-customer.dto';
|
||||
import { ListCustomersDto } from './dto/list-customers.dto';
|
||||
@@ -35,6 +36,16 @@ export class CustomersController {
|
||||
return this.service.list(businessId, query, user);
|
||||
}
|
||||
|
||||
@Get('activity')
|
||||
@RequireBusinessPermission('orders.read')
|
||||
activity(
|
||||
@Param('businessId') businessId: string,
|
||||
@Query() query: DailyActivityQueryDto,
|
||||
@CurrentUser() user: AuthUser,
|
||||
) {
|
||||
return this.service.dailyActivity(businessId, query.days, user);
|
||||
}
|
||||
|
||||
@Get('search')
|
||||
@RequireBusinessPermission('orders.create')
|
||||
search(
|
||||
|
||||
@@ -3,6 +3,10 @@ import { Prisma } from '@prisma/client';
|
||||
import * as bcrypt from 'bcrypt';
|
||||
import { AuthUser } from '../auth/auth.types';
|
||||
import { PermissionsService } from '../auth/permissions.service';
|
||||
import {
|
||||
buildDualDailyActivitySeries,
|
||||
startOfLocalDay,
|
||||
} from '../common/daily-activity';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import { CreateCustomerDto } from './dto/create-customer.dto';
|
||||
import { ListCustomersDto } from './dto/list-customers.dto';
|
||||
@@ -94,6 +98,48 @@ export class CustomersService {
|
||||
};
|
||||
}
|
||||
|
||||
/** Lightweight daily registration + active-login counts for dashboard charts. */
|
||||
async dailyActivity(
|
||||
businessIdRaw: string,
|
||||
daysRaw: number | undefined,
|
||||
actor: AuthUser,
|
||||
) {
|
||||
const businessId = BigInt(businessIdRaw);
|
||||
await this.assertPermission(businessId, actor.id, 'orders.read');
|
||||
|
||||
const days = Math.min(Math.max(daysRaw ?? 30, 1), 90);
|
||||
const from = startOfLocalDay(days - 1);
|
||||
|
||||
const [registeredRows, activeRows] = await Promise.all([
|
||||
this.prisma.$queryRaw<{ day: Date; count: number }[]>(
|
||||
Prisma.sql`
|
||||
SELECT created_at::date AS day,
|
||||
COUNT(*)::int AS count
|
||||
FROM business_customers
|
||||
WHERE business_id = ${businessId}
|
||||
AND created_at >= ${from}
|
||||
GROUP BY 1
|
||||
ORDER BY 1
|
||||
`,
|
||||
),
|
||||
this.prisma.$queryRaw<{ day: Date; count: number }[]>(
|
||||
Prisma.sql`
|
||||
SELECT u.last_login_at::date AS day,
|
||||
COUNT(*)::int AS count
|
||||
FROM business_customers bc
|
||||
JOIN users u ON u.id = bc.user_id
|
||||
WHERE bc.business_id = ${businessId}
|
||||
AND u.last_login_at IS NOT NULL
|
||||
AND u.last_login_at >= ${from}
|
||||
GROUP BY 1
|
||||
ORDER BY 1
|
||||
`,
|
||||
),
|
||||
]);
|
||||
|
||||
return buildDualDailyActivitySeries(days, registeredRows, activeRows);
|
||||
}
|
||||
|
||||
async search(
|
||||
businessIdRaw: string,
|
||||
query: SearchCustomersDto,
|
||||
|
||||
Reference in New Issue
Block a user