Skip to content

Commit 79170d1

Browse files
authored
th-169: Drivers table (#228)
* th-169: * driver flow added user to response * th-169: * driver types * th-169: * driver service added findPageOfDrivers * th-169: * driver service added total and createdAt * th-169: * driver types * th-169: + driver table * th-169: + driver table flow * th-169: * driver entity * th-169: * driver api types * th-169: * drivers acrions added notification service * th-169: * drivers routes and types * th-169: * imports fixed props * th-169: * driver actions fixed rejectWithValue * th-169: * swagger documentation * th-169: * driver slice * th-169: * drivers slice renamed * th-169: * driver table added queries and enmpty data message * th-169: * table fixed message with loading * th-169: * table added styles * th-169: * driver table changed styles * th-169: * driver service changed types * th-169: * empty table message * th-169: * driver actions refactored addDriver * th-169: * useAppTable * th-169: * table message
1 parent c48cff3 commit 79170d1

File tree

65 files changed

+842
-110
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+842
-110
lines changed

.eslintrc.yml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,9 @@ rules:
124124
'@typescript-eslint/semi':
125125
- error
126126
- always
127+
'@typescript-eslint/no-unused-vars':
128+
- error
129+
- ignoreRestSiblings: true
127130

128131
overrides:
129132
- files:

backend/src/packages/business/business.controller.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,15 @@ import {
2525
type BusinessGetRequestParameters,
2626
type BusinessUpdateRequestDto,
2727
type BusinessUpdateRequestParameters,
28+
type GetPaginatedPageQuery,
2829
} from './libs/types/types.js';
2930
import {
3031
businessAddRequestBody,
3132
businessDeleteParameters,
3233
businessGetParameters,
3334
businessUpdateParameters,
3435
businessUpdateRequestBody,
36+
commonGetPageQuery,
3537
} from './libs/validation-schemas/validation-schemas.js';
3638

3739
/**
@@ -354,9 +356,13 @@ class BusinessController extends Controller {
354356
path: BusinessApiPath.DRIVERS,
355357
method: 'GET',
356358
authStrategy: defaultStrategies,
359+
validation: {
360+
query: commonGetPageQuery,
361+
},
357362
handler: (options) =>
358363
this.findAllDrivers(
359364
options as ApiHandlerOptions<{
365+
query: GetPaginatedPageQuery;
360366
user: UserEntityObjectWithGroupT;
361367
}>,
362368
),
@@ -744,18 +750,27 @@ class BusinessController extends Controller {
744750
* content:
745751
* application/json:
746752
* schema:
747-
* type: array
748-
* items:
749-
* $ref: '#/components/schemas/Driver'
753+
* type: object
754+
* properties:
755+
* items:
756+
* type: array
757+
* items:
758+
* $ref: '#/components/schemas/Driver'
759+
* total:
760+
* type: string
761+
* example: 1
762+
*
750763
*/
751764

752765
private async findAllDrivers(
753766
options: ApiHandlerOptions<{
767+
query: GetPaginatedPageQuery;
754768
user: UserEntityObjectWithGroupT;
755769
}>,
756770
): Promise<ApiHandlerResponse> {
757771
const drivers = await this.businessService.findAllDriversByBusinessId(
758772
options.user.id,
773+
options.query,
759774
);
760775

761776
return {

backend/src/packages/business/business.service.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
type BusinessCreatePayload,
2020
type BusinessEntityT,
2121
type BusinessUpdateResponseDto,
22+
type GetPaginatedPageQuery,
2223
} from './libs/types/types.js';
2324

2425
class BusinessService implements IService {
@@ -170,6 +171,7 @@ class BusinessService implements IService {
170171

171172
public async findAllDriversByBusinessId(
172173
ownerId: number,
174+
query: GetPaginatedPageQuery,
173175
): Promise<DriverGetAllResponseDto> {
174176
const business = await this.findByOwnerId(ownerId);
175177

@@ -180,7 +182,10 @@ class BusinessService implements IService {
180182
});
181183
}
182184

183-
return await this.driverService.findAllByBusinessId(business.id);
185+
return await this.driverService.findAllByBusinessId({
186+
businessId: business.id,
187+
query,
188+
});
184189
}
185190

186191
public async deleteDriver(

backend/src/packages/business/libs/types/types.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@ export {
88
type BusinessUpdateRequestDto,
99
type BusinessUpdateRequestParameters,
1010
type BusinessUpdateResponseDto,
11+
type GetPaginatedPageQuery,
1112
} from 'shared/build/index.js';

backend/src/packages/business/libs/validation-schemas/validation-schemas.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ export {
44
businessGetParameters,
55
businessUpdateParameters,
66
businessUpdateRequestBody,
7+
commonGetPageQuery,
78
} from 'shared/build/index.js';

backend/src/packages/drivers/driver.entity.ts

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { type IEntity } from '~/libs/interfaces/entity.interface.js';
22
import { type NullableProperties } from '~/libs/types/types.js';
33

4+
import { type UserEntityT } from '../users/users.js';
45
import { type DriverEntity as DriverEntityT } from './libs/types/types.js';
56

67
class DriverEntity implements IEntity {
@@ -12,42 +13,57 @@ class DriverEntity implements IEntity {
1213

1314
private businessId: DriverEntityT['businessId'];
1415

16+
private createdAt: DriverEntityT['createdAt'] | null;
17+
18+
private user?: UserEntityT;
19+
1520
private constructor({
1621
id,
1722
driverLicenseNumber,
1823
userId,
1924
businessId,
20-
}: NullableProperties<DriverEntityT, 'id'>) {
25+
createdAt,
26+
user,
27+
}: NullableProperties<DriverEntityT, 'id' | 'createdAt'> & {
28+
user?: UserEntityT;
29+
}) {
2130
this.id = id;
2231
this.driverLicenseNumber = driverLicenseNumber;
2332
this.userId = userId;
2433
this.businessId = businessId;
34+
this.createdAt = createdAt;
35+
this.user = user;
2536
}
2637

2738
public static initialize({
2839
id,
2940
driverLicenseNumber,
3041
userId,
3142
businessId,
32-
}: DriverEntityT): DriverEntity {
43+
createdAt,
44+
user,
45+
}: DriverEntityT & { user?: UserEntityT }): DriverEntity {
3346
return new DriverEntity({
3447
id,
3548
driverLicenseNumber,
3649
userId,
3750
businessId,
51+
createdAt,
52+
user,
3853
});
3954
}
4055

4156
public static initializeNew({
4257
driverLicenseNumber,
4358
userId,
4459
businessId,
45-
}: Omit<DriverEntityT, 'id'>): DriverEntity {
60+
}: Omit<DriverEntityT, 'id' | 'createdAt'>): DriverEntity {
4661
return new DriverEntity({
4762
id: null,
4863
driverLicenseNumber,
4964
userId,
5065
businessId,
66+
createdAt: null,
5167
});
5268
}
5369

@@ -57,6 +73,7 @@ class DriverEntity implements IEntity {
5773
driverLicenseNumber: this.driverLicenseNumber,
5874
userId: this.userId,
5975
businessId: this.businessId,
76+
createdAt: this.createdAt as string,
6077
};
6178
}
6279

@@ -65,6 +82,18 @@ class DriverEntity implements IEntity {
6582
driverLicenseNumber: this.driverLicenseNumber,
6683
userId: this.userId,
6784
businessId: this.businessId,
85+
createdAt: this.createdAt as string,
86+
};
87+
}
88+
89+
public toObjectWithUser(): DriverEntityT & { user: UserEntityT } {
90+
return {
91+
id: this.id as number,
92+
driverLicenseNumber: this.driverLicenseNumber,
93+
userId: this.userId,
94+
businessId: this.businessId,
95+
createdAt: this.createdAt as string,
96+
user: this.user as UserEntityT,
6897
};
6998
}
7099
}

backend/src/packages/drivers/driver.repository.ts

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { type SQL, and, eq, or } from 'drizzle-orm';
1+
import { type SQL, and, desc, eq, or, sql } from 'drizzle-orm';
22

33
import { AppErrorMessage } from '~/libs/enums/enums.js';
44
import { ApplicationError } from '~/libs/exceptions/exceptions.js';
@@ -9,6 +9,8 @@ import { type OperationResult } from '~/libs/types/types.js';
99

1010
import { DriverEntity } from './driver.entity.js';
1111
import { type DriverEntity as DriverEntityT } from './drivers.js';
12+
import { countOffsetByQuery } from './libs/helpers/helpers.js';
13+
import { type GetPaginatedPageQuery } from './libs/types/types.js';
1214

1315
class DriverRepository implements IRepository {
1416
private db: Pick<IDatabase, 'driver'>;
@@ -24,8 +26,8 @@ class DriverRepository implements IRepository {
2426
this.driverSchema = driverSchema;
2527
}
2628

27-
public find(
28-
partial: Partial<DriverEntityT>,
29+
public async find(
30+
partial: Partial<Omit<DriverEntityT, 'user'>>,
2931
): ReturnType<IRepository<DriverEntityT>['find']> {
3032
const queries = Object.entries(partial).map(([key, value]) =>
3133
eq(
@@ -36,22 +38,41 @@ class DriverRepository implements IRepository {
3638

3739
const finalQuery = queries.length === 1 ? queries[0] : and(...queries);
3840

39-
return this.db
41+
const drivers = await this.db
4042
.driver()
41-
.query.drivers.findMany({ where: finalQuery })
43+
.query.drivers.findMany({ where: finalQuery, with: { user: true } })
4244
.execute();
45+
46+
return drivers.map(({ createdAt, updatedAt, ...pureDriver }) =>
47+
DriverEntity.initialize({
48+
...pureDriver,
49+
createdAt: createdAt.toISOString(),
50+
}).toObject(),
51+
);
4352
}
4453

4554
public async findAllByBusinessId(
4655
businessId: number,
56+
query: GetPaginatedPageQuery,
4757
): Promise<DriverEntity[]> {
58+
const offset = countOffsetByQuery(query);
4859
const drivers = await this.db
4960
.driver()
50-
.select()
51-
.from(this.driverSchema)
52-
.where(eq(this.driverSchema.businessId, businessId));
61+
.query.drivers.findMany({
62+
limit: query.size,
63+
offset,
64+
where: eq(this.driverSchema.businessId, businessId),
65+
with: { user: true },
66+
orderBy: [desc(this.driverSchema.createdAt)],
67+
})
68+
.execute();
5369

54-
return drivers.map((it) => DriverEntity.initialize(it));
70+
return drivers.map(({ createdAt, ...pureDriver }) =>
71+
DriverEntity.initialize({
72+
...pureDriver,
73+
createdAt: createdAt.toISOString(),
74+
}),
75+
);
5576
}
5677

5778
public async checkExists({
@@ -76,7 +97,7 @@ class DriverRepository implements IRepository {
7697
});
7798
}
7899

79-
const [driver]: DriverEntityT[] = await this.db
100+
const [driver] = await this.db
80101
.driver()
81102
.select()
82103
.from(this.driverSchema)
@@ -90,14 +111,17 @@ class DriverRepository implements IRepository {
90111
public async create(entity: DriverEntity): Promise<DriverEntity> {
91112
const { driverLicenseNumber, userId, businessId } = entity.toNewObject();
92113

93-
const [item] = await this.db
114+
const [{ createdAt, ...pureDriver }] = await this.db
94115
.driver()
95116
.insert(this.driverSchema)
96117
.values({ driverLicenseNumber, userId, businessId })
97118
.returning()
98119
.execute();
99120

100-
return DriverEntity.initialize(item);
121+
return DriverEntity.initialize({
122+
...pureDriver,
123+
createdAt: createdAt.toISOString(),
124+
});
101125
}
102126

103127
public async update({
@@ -107,15 +131,18 @@ class DriverRepository implements IRepository {
107131
id: number;
108132
payload: Partial<Pick<DriverEntityT, 'driverLicenseNumber'>>;
109133
}): Promise<DriverEntity> {
110-
const [item] = await this.db
134+
const [{ createdAt, ...pureDriver }] = await this.db
111135
.driver()
112136
.update(this.driverSchema)
113137
.set(payload)
114138
.where(eq(this.driverSchema.id, id))
115139
.returning()
116140
.execute();
117141

118-
return DriverEntity.initialize(item);
142+
return DriverEntity.initialize({
143+
...pureDriver,
144+
createdAt: createdAt.toISOString(),
145+
});
119146
}
120147

121148
public async delete(id: number): Promise<boolean> {
@@ -128,6 +155,16 @@ class DriverRepository implements IRepository {
128155

129156
return Boolean(item);
130157
}
158+
159+
public async getTotal(id: number): Promise<number> {
160+
const [driver] = await this.db
161+
.driver()
162+
.select({ count: sql<number>`count(*)` })
163+
.from(this.driverSchema)
164+
.where(eq(this.driverSchema.businessId, id));
165+
166+
return driver.count;
167+
}
131168
}
132169

133170
export { DriverRepository };

backend/src/packages/drivers/driver.service.ts

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,17 @@ import { UserGroupKey } from '../auth/libs/enums/enums.js';
99
import { DriverEntity } from '../drivers/driver.entity.js';
1010
import { type DriverRepository } from '../drivers/driver.repository.js';
1111
import {
12-
type DriverAddPayload,
12+
type DriverAddPayloadWithBusinessId,
1313
type DriverAddResponseWithGroup,
1414
type DriverCreateUpdateResponseDto,
1515
type DriverEntity as DriverEntityT,
1616
type DriverGetAllResponseDto,
17+
type DriverGetDriversPayloadWithBusinessId,
1718
type DriverUpdatePayload,
1819
} from '../drivers/libs/types/types.js';
1920
import { type GroupService } from '../groups/group.service.js';
2021
import { type UserService } from '../users/user.service.js';
22+
import { convertToDriverUser } from './libs/helpers/helpers.js';
2123

2224
class DriverService implements IService {
2325
private driverRepository: DriverRepository;
@@ -79,20 +81,26 @@ class DriverService implements IService {
7981
return driver ? DriverEntity.initialize(driver).toObject() : null;
8082
}
8183

82-
public async findAllByBusinessId(
83-
businessId: number,
84-
): Promise<DriverGetAllResponseDto> {
85-
const items = await this.driverRepository.findAllByBusinessId(businessId);
84+
public async findAllByBusinessId({
85+
businessId,
86+
query,
87+
}: DriverGetDriversPayloadWithBusinessId): Promise<DriverGetAllResponseDto> {
88+
const items = await this.driverRepository.findAllByBusinessId(
89+
businessId,
90+
query,
91+
);
92+
const total = await this.driverRepository.getTotal(businessId);
8693

8794
return {
88-
items: items.map((it) => it.toObject()),
95+
items: items.map((item) => convertToDriverUser(item)),
96+
total,
8997
};
9098
}
9199

92100
public async create({
93101
payload,
94102
businessId,
95-
}: DriverAddPayload): Promise<DriverAddResponseWithGroup> {
103+
}: DriverAddPayloadWithBusinessId): Promise<DriverAddResponseWithGroup> {
96104
const { password, email, lastName, firstName, phone, driverLicenseNumber } =
97105
payload;
98106

0 commit comments

Comments
 (0)