moahmedwafy commited on
Commit
fa68931
·
1 Parent(s): 19cd995

feat: streaks endpoint

Browse files
:w ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { serialize } from "@helpers/serialize";
2
+ import { SwaggerResponseProperty } from "@lib/decorators/swagger-response-property.decorator";
3
+ import { Expose, Transform } from "class-transformer";
4
+
5
+ class HSDaysSerialization {
6
+ @Expose()
7
+ @SwaggerResponseProperty('string')
8
+ day: string;
9
+
10
+ @Expose()
11
+ @SwaggerResponseProperty('number')
12
+ points: number;
13
+ }
14
+
15
+ export class HomeStreakSerialization {
16
+ @Expose()
17
+ @Transform((value) => (value as any).map((day) => serialize(day, HSDaysSerialization)))
18
+ @SwaggerResponseProperty({ type: [HSDaysSerialization]})
19
+ days: HSDaysSerialization[];
20
+ }
package-lock.json CHANGED
@@ -30,6 +30,7 @@
30
  "tsc-alias": "^1.8.8"
31
  },
32
  "devDependencies": {
 
33
  "@types/express": "^4.17.21",
34
  "@types/swagger-ui-express": "^4.1.6",
35
  "nodemon": "^3.0.2",
@@ -51,6 +52,22 @@
51
  "node": ">=12"
52
  }
53
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  "node_modules/@hapi/address": {
55
  "version": "4.1.0",
56
  "resolved": "https://registry.npmjs.org/@hapi/address/-/address-4.1.0.tgz",
 
30
  "tsc-alias": "^1.8.8"
31
  },
32
  "devDependencies": {
33
+ "@faker-js/faker": "^8.4.1",
34
  "@types/express": "^4.17.21",
35
  "@types/swagger-ui-express": "^4.1.6",
36
  "nodemon": "^3.0.2",
 
52
  "node": ">=12"
53
  }
54
  },
55
+ "node_modules/@faker-js/faker": {
56
+ "version": "8.4.1",
57
+ "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-8.4.1.tgz",
58
+ "integrity": "sha512-XQ3cU+Q8Uqmrbf2e0cIC/QN43sTBSC8KF12u29Mb47tWrt2hAgBXSgpZMj4Ao8Uk0iJcU99QsOCaIL8934obCg==",
59
+ "dev": true,
60
+ "funding": [
61
+ {
62
+ "type": "opencollective",
63
+ "url": "https://opencollective.com/fakerjs"
64
+ }
65
+ ],
66
+ "engines": {
67
+ "node": "^14.17.0 || ^16.13.0 || >=18.0.0",
68
+ "npm": ">=6.14.13"
69
+ }
70
+ },
71
  "node_modules/@hapi/address": {
72
  "version": "4.1.0",
73
  "resolved": "https://registry.npmjs.org/@hapi/address/-/address-4.1.0.tgz",
package.json CHANGED
@@ -14,6 +14,7 @@
14
  "author": "",
15
  "license": "ISC",
16
  "devDependencies": {
 
17
  "@types/express": "^4.17.21",
18
  "@types/swagger-ui-express": "^4.1.6",
19
  "nodemon": "^3.0.2",
 
14
  "author": "",
15
  "license": "ISC",
16
  "devDependencies": {
17
+ "@faker-js/faker": "^8.4.1",
18
  "@types/express": "^4.17.21",
19
  "@types/swagger-ui-express": "^4.1.6",
20
  "nodemon": "^3.0.2",
src/common/interfaces/user-request.interface.ts ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ import { Request } from "express";
2
+ import { IJwtLoginPayload } from "./jwt-payload.interface";
3
+
4
+ export interface IUserRequest extends Request {
5
+ jwtPayload?: IJwtLoginPayload;
6
+ }
src/modules/users/modules/home/controllers/home.controller.ts CHANGED
@@ -1,7 +1,6 @@
1
  import { UserRegisteredWorkoutsService } from "../../user-registered-workouts/services/user-registered-workouts.service";
2
- import { UserRegisteredMealPlansService } from "../../user-registered-meal-plans/services/user-registered-meal-plans.service";
3
  import { UserService } from "../../users/services/users.service";
4
- import { Request, Response } from "express";
5
  import { JsonResponse } from "@lib/responses/json-response";
6
  import { asyncHandler } from "@helpers/async-handler";
7
  import { BaseController } from "@lib/controllers/controller.base";
@@ -13,30 +12,63 @@ import { SwaggerGet } from "@lib/decorators/swagger-routes.decorator";
13
  import { SwaggerSummary } from "@lib/decorators/swagger-summary.decorator";
14
  import { SwaggerDescription } from "@lib/decorators/swagger-description.decorator";
15
  import { SwaggerResponse } from "@lib/decorators/swagger-response.decorator";
16
- import { HomeSerialization } from "common/serializers/home.serialization";
 
 
 
 
 
 
17
 
18
 
19
- interface userRequest extends Request {
20
- jwtPayload?: any;
21
- }
22
-
23
  @Controller("/user/homePage")
24
  @ControllerMiddleware(UsersGuardMiddleware())
25
  export class homePageController extends BaseController {
26
  private userRegisteredWorkoutsService = new UserRegisteredWorkoutsService();
27
- private userRegisteredMealPlansService = new UserRegisteredMealPlansService();
28
  private userService = new UserService();
 
29
 
30
  setRoutes(): void {
31
  this.router.get("/", asyncHandler(this.getHomePage));
 
32
  }
33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
  @SwaggerGet()
36
  @SwaggerResponse(HomeSerialization)
37
  @SwaggerSummary("Home")
38
  @SwaggerDescription("Get home page")
39
- getHomePage = async (req: userRequest, res: Response) => {
40
 
41
  const user = await this.userService.findOneOrFail(
42
  { _id: req.jwtPayload.id },
 
1
  import { UserRegisteredWorkoutsService } from "../../user-registered-workouts/services/user-registered-workouts.service";
 
2
  import { UserService } from "../../users/services/users.service";
3
+ import { Response } from "express";
4
  import { JsonResponse } from "@lib/responses/json-response";
5
  import { asyncHandler } from "@helpers/async-handler";
6
  import { BaseController } from "@lib/controllers/controller.base";
 
12
  import { SwaggerSummary } from "@lib/decorators/swagger-summary.decorator";
13
  import { SwaggerDescription } from "@lib/decorators/swagger-description.decorator";
14
  import { SwaggerResponse } from "@lib/decorators/swagger-response.decorator";
15
+ import { HomeSerialization } from "../responses/home.serialization";
16
+ import { HomeStreakSerialization } from "../responses/home-streak.serialization";
17
+ import { SwaggerQuery } from "@lib/decorators/swagger-query.decorator";
18
+ import { queryValidator } from "@helpers/validation.helper";
19
+ import { homeStreakQueryValidation } from "../validations/home-streak.query.validation";
20
+ import { UserHomeService } from "../services/user-home.service";
21
+ import { IUserRequest } from "@common/interfaces/user-request.interface";
22
 
23
 
 
 
 
 
24
  @Controller("/user/homePage")
25
  @ControllerMiddleware(UsersGuardMiddleware())
26
  export class homePageController extends BaseController {
27
  private userRegisteredWorkoutsService = new UserRegisteredWorkoutsService();
 
28
  private userService = new UserService();
29
+ private userHomeService = new UserHomeService();
30
 
31
  setRoutes(): void {
32
  this.router.get("/", asyncHandler(this.getHomePage));
33
+ this.router.get("/streak", queryValidator(homeStreakQueryValidation), asyncHandler(this.getHomePageStreak));
34
  }
35
 
36
+ @SwaggerGet('/streak')
37
+ @SwaggerResponse(HomeStreakSerialization)
38
+ @SwaggerQuery({
39
+ startDate: {
40
+ type: "string",
41
+ required: true,
42
+ },
43
+ endDate: {
44
+ type: "string",
45
+ required: true,
46
+ },
47
+ })
48
+ @SwaggerSummary("Home Streak Weeks")
49
+ @SwaggerDescription("Get home page streak weeks")
50
+ getHomePageStreak = async (req: IUserRequest, res: Response) => {
51
+ // getting the query params
52
+ const startDate = new Date(req.query.startDate as string);
53
+ const endDate = new Date(req.query.endDate as string);
54
+
55
+ // getting the streak weeks
56
+ const streak = await this.userHomeService.getHomePageStreak(req.jwtPayload.id, startDate, endDate);
57
+
58
+ // return response
59
+ return JsonResponse.success(
60
+ {
61
+ data: serialize(streak, HomeStreakSerialization)
62
+ },
63
+ res
64
+ );
65
+ };
66
 
67
  @SwaggerGet()
68
  @SwaggerResponse(HomeSerialization)
69
  @SwaggerSummary("Home")
70
  @SwaggerDescription("Get home page")
71
+ getHomePage = async (req: IUserRequest, res: Response) => {
72
 
73
  const user = await this.userService.findOneOrFail(
74
  { _id: req.jwtPayload.id },
src/modules/users/modules/home/responses/home-streak.serialization.ts ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { SwaggerResponseProperty } from "@lib/decorators/swagger-response-property.decorator";
2
+ import { Expose } from "class-transformer";
3
+
4
+ class HSDaysSerialization {
5
+ @Expose()
6
+ @SwaggerResponseProperty('string')
7
+ day: string;
8
+
9
+ @Expose()
10
+ @SwaggerResponseProperty('number')
11
+ points: number;
12
+ }
13
+
14
+ export class HomeStreakSerialization {
15
+ @Expose()
16
+ @SwaggerResponseProperty({ type: [HSDaysSerialization]})
17
+ days: HSDaysSerialization[];
18
+ }
src/{common/serializers → modules/users/modules/home/responses}/home.serialization.ts RENAMED
@@ -118,7 +118,6 @@ class UserHome {
118
  }
119
 
120
  export class HomeSerialization {
121
-
122
  @Expose()
123
  @SwaggerResponseProperty({ type: UserHome })
124
  @Transform(({ value }) => serialize(value, UserHome))
@@ -132,4 +131,4 @@ export class HomeSerialization {
132
  @Expose({ name: "myMealPlan" })
133
  @SwaggerResponseProperty({ type: {} })
134
  myMealPlan: any;
135
- }
 
118
  }
119
 
120
  export class HomeSerialization {
 
121
  @Expose()
122
  @SwaggerResponseProperty({ type: UserHome })
123
  @Transform(({ value }) => serialize(value, UserHome))
 
131
  @Expose({ name: "myMealPlan" })
132
  @SwaggerResponseProperty({ type: {} })
133
  myMealPlan: any;
134
+ }
src/modules/users/modules/home/services/user-home.service.ts ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { HomeStreakSerialization } from "../responses/home-streak.serialization";
2
+ import { faker } from '@faker-js/faker';
3
+
4
+ export class UserHomeService {
5
+ private getDaysArray(startDate: Date, endDate: Date): string[] {
6
+ const days = [];
7
+ for (let day = startDate; day <= endDate; day.setDate(day.getDate() + 1)) {
8
+ days.push(day.toLocaleString('en-US', { weekday: 'long' }).toLowerCase());
9
+ }
10
+ return days;
11
+ }
12
+
13
+ async getHomePageStreak(_userId: string, startDate: Date, endDate: Date): Promise<HomeStreakSerialization> {
14
+ // list day names in between the start and end date
15
+ const days = this.getDaysArray(startDate, endDate);
16
+
17
+ return {
18
+ days: days.map(day => ({
19
+ day: day,
20
+ points: faker.number.int({ min: 0, max: 100 }),
21
+ })),
22
+ }
23
+ }
24
+ }
src/modules/users/modules/home/validations/home-streak.query.validation.ts ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as joi from "joi";
2
+ import { createSchema } from "@helpers/create-schema";
3
+
4
+ export interface IHomeStreakQuery {
5
+ startDate: string;
6
+ endDate: string;
7
+ }
8
+
9
+ export const homeStreakQueryKeys = {
10
+ startDate: joi.string().pattern(new RegExp("^[0-9]{4}-[0-9]{2}-[0-9]{2}$")).required().messages({
11
+ "string.base": "startDate must be a string",
12
+ "string.pattern.base": "startDate must be a valid date",
13
+ "any.required": "startDate is required",
14
+ }),
15
+ endDate: joi.string().pattern(new RegExp("^[0-9]{4}-[0-9]{2}-[0-9]{2}$")).required().messages({
16
+ "string.base": "endDate must be a string",
17
+ "string.pattern.base": "endDate must be a valid date",
18
+ "any.required": "endDate is required",
19
+ })
20
+ };
21
+
22
+ export const homeStreakQueryValidation = createSchema<IHomeStreakQuery>(homeStreakQueryKeys);