Skip to content
This repository was archived by the owner on Feb 28, 2026. It is now read-only.

Commit de10136

Browse files
authored
Merge pull request #63 from WildCodeSchool/feature/staff-bonus
Feature/staff bonus
2 parents 2078595 + ea50a87 commit de10136

File tree

8 files changed

+177
-54
lines changed

8 files changed

+177
-54
lines changed

packages/backend/api/src/albums/albums.ts

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,32 @@
1-
import express from 'express';
1+
import { type Request, Router } from 'express';
22

33
import { db } from '@app/backend-shared';
44

5-
const albumsRouter = express.Router();
5+
const albumsRouter = Router();
66

7-
albumsRouter.post('/create', async (req, res) => {
7+
albumsRouter.post('/create', async (req: Request, res) => {
8+
const userId = req.userId;
9+
if (userId === undefined) {
10+
res.json({
11+
ok: false,
12+
});
13+
return;
14+
}
815
const { artistHiredId, singleName, singleId, genreId } = req.body;
916
try {
1017
if (!Number(artistHiredId)) {
1118
res.status(400).json({ error: 'artistId is required' });
1219
return;
1320
}
1421

22+
const bonus = await db
23+
.selectFrom('labels')
24+
.leftJoin('staff_label', 'staff_label.labels_id', 'labels.id')
25+
.leftJoin('staff', 'staff.id', 'staff_label.staff_id')
26+
.select([db.fn.sum('staff.bonus').as('staff_bonus')])
27+
.where('labels.users_id', '=', userId)
28+
.executeTakeFirst();
29+
1530
const albumId = await db
1631
.insertInto('albums')
1732
.values({
@@ -20,7 +35,7 @@ albumsRouter.post('/create', async (req, res) => {
2035
genres_id: genreId,
2136
exp_value: 100,
2237
sales: 0,
23-
money_earned: 6000,
38+
money_earned: 6000 * (Number(bonus?.staff_bonus) / 100 + 1),
2439
score: 0,
2540
})
2641
.executeTakeFirst();

packages/backend/api/src/artists/artists.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
// import express from 'express';
21
import { type Request, Router } from 'express';
32
import { jsonArrayFrom } from 'kysely/helpers/mysql';
43

packages/backend/api/src/games/get-staff.ts

Lines changed: 26 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,47 @@
1-
import express from 'express';
1+
import { type Request, Router } from 'express';
22

33
import { db } from '@app/backend-shared';
44

5-
const getStaffRouter = express.Router();
5+
const getStaffRouter = Router();
66

7-
async function getStaff() {
7+
async function getStaff(userId: number) {
88
return db
9-
109
.selectFrom('staff')
11-
.leftJoin('staff_label', 'staff_label.staff_id', 'staff.id')
1210
.select([
1311
'staff.id',
1412
'staff.job',
1513
'staff.bonus',
1614
'staff.price',
1715
'staff.image',
1816
])
19-
.where('staff_label.staff_id', 'is', null)
17+
.where((eb) =>
18+
eb.not(
19+
eb.exists(
20+
eb
21+
.selectFrom('staff_label')
22+
.leftJoin('labels', 'labels.id', 'staff_label.labels_id')
23+
.select('staff_label.id')
24+
.whereRef('staff_label.staff_id', '=', 'staff.id')
25+
.where('labels.users_id', '=', userId),
26+
),
27+
),
28+
)
2029
.execute();
2130
}
31+
2232
export type Staff = Awaited<ReturnType<typeof getStaff>>[number];
2333

24-
getStaffRouter.get('/staff', async (req, res) => {
34+
getStaffRouter.get('/staff', async (req: Request, res) => {
35+
const userId = req.userId;
36+
if (userId === undefined) {
37+
res.json({
38+
ok: false,
39+
});
40+
return;
41+
}
42+
2543
try {
26-
const staff = await getStaff();
44+
const staff = await getStaff(userId);
2745
res.json({ ok: true, staff });
2846
return;
2947
} catch (error) {

packages/backend/api/src/singles/singles.ts

Lines changed: 60 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,6 @@ singlesRouter.get('/', async (req: Request, res) => {
9393

9494
singlesRouter.post('/', async (req: Request, res) => {
9595
const { artistHiredId, singleName, genreId } = req.body;
96-
console.log(req.body);
9796

9897
const userId = req.userId;
9998
if (userId === undefined) {
@@ -122,6 +121,66 @@ singlesRouter.post('/', async (req: Request, res) => {
122121
})
123122
.execute();
124123

124+
const milestones = await db
125+
.selectFrom('milestones')
126+
.leftJoin('artists_hired', 'artists_hired.milestones_id', 'milestones.id')
127+
.select('milestones.value')
128+
.where('artists_hired.id', '=', artistHiredId)
129+
.execute();
130+
131+
const gain = milestones.map((label) => {
132+
const newGain = Number(label.value) / 100;
133+
return newGain;
134+
});
135+
136+
const notoriety = await db
137+
.selectFrom('artists_hired')
138+
.select('artists_hired.notoriety')
139+
.where('artists_hired.id', '=', artistHiredId)
140+
.executeTakeFirst();
141+
142+
if (!notoriety) {
143+
res.status(400).json({ error: 'No milestone found' });
144+
return;
145+
}
146+
147+
if (notoriety.notoriety >= 5) {
148+
res.json({ message: 'max 5' });
149+
return;
150+
}
151+
152+
await db
153+
.updateTable('artists_hired')
154+
.set((eb) => ({
155+
notoriety: eb('notoriety', '+', Number(gain)),
156+
}))
157+
.where('artists_hired.id', '=', artistHiredId)
158+
.execute();
159+
160+
const newMilestone = await db
161+
.selectFrom('milestones')
162+
.select('id')
163+
.where('value', '<=', Number(notoriety.notoriety) * 10)
164+
.orderBy('id', 'desc')
165+
.limit(1)
166+
.executeTakeFirst();
167+
168+
if (!newMilestone) {
169+
res.status(400).json({ error: 'No milestone found' });
170+
return;
171+
}
172+
173+
if (newMilestone.id >= 5) {
174+
res.json({ message: 'max 5' });
175+
return;
176+
}
177+
178+
await db
179+
.updateTable('artists_hired')
180+
.set({ milestones_id: newMilestone.id })
181+
.where('id', '=', artistHiredId)
182+
.execute();
183+
125184
res.status(201).json({ success: true });
126185
return;
127186
} catch (err) {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { type Kysely, sql } from 'kysely';
2+
3+
import type { DB } from '@app/shared';
4+
5+
export async function up(db: Kysely<DB>): Promise<void> {
6+
// Migration code that update the database to the desired state.
7+
await db.transaction().execute(async (trx) => {
8+
await sql`
9+
CREATE TABLE price (
10+
id int8 AUTO_INCREMENT PRIMARY KEY,
11+
price INT NULL
12+
);
13+
`.execute(trx);
14+
});
15+
}
16+
17+
export async function down(db: Kysely<DB>): Promise<void> {
18+
// Migration code that reverts the database to the previous state.
19+
await db.transaction().execute(async (trx) => {
20+
await sql`
21+
DROP TABLE IF EXISTS price;
22+
`.execute(trx);
23+
});
24+
}

packages/frontend/web/src/components/arrow-left.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { useNavigate } from 'react-router-dom';
33
export function ArrowLeft() {
44
const navigate = useNavigate();
55
return (
6-
<div className='mb-4 flex w-full items-center justify-between'>
6+
<div className='absolute mb-4 flex w-full items-center justify-between'>
77
<button
88
onClick={async () => {
99
await navigate(-1);

packages/frontend/web/src/pages/hire-staff.tsx

Lines changed: 41 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -96,48 +96,50 @@ export default function HireArtist() {
9696
};
9797

9898
return (
99-
<div className='bg-primary flex min-h-screen flex-col items-center px-4 py-6'>
100-
<div className='mb-4 flex w-full items-center justify-between'>
101-
<button type='button'>
102-
<ArrowLeft />
103-
</button>
104-
<h1 className='text-secondary text-center text-2xl font-bold underline underline-offset-4'>
99+
<>
100+
<ArrowLeft />
101+
<div className='flex min-h-screen flex-col items-center bg-white py-6'>
102+
<h1 className='text-secondary w-full text-center text-2xl font-bold underline underline-offset-4'>
105103
{'HIRE STAFF'}
106104
</h1>
107-
<div className='h-6 w-6' />
108-
</div>
109-
110-
<div className='mb-8 flex flex-col text-xl font-medium text-teal-800'>
111-
{'STAFF'}
112-
</div>
113-
<div className='grid grid-cols-2 gap-4'>
114-
{sortedStaff.slice(0, visibleCount).map((staff) => (
115-
<StaffCardHire
116-
key={staff.id}
117-
staff={staff}
118-
onHire={async () => {
119-
if (labelId === undefined) {
120-
setMessageBudget('Label or budget info not loaded yet.');
121-
return;
122-
}
123-
try {
124-
void handleStaffArtist(staff.id, staff.price, labelId, budget);
125-
await navigate('/main-menu');
126-
} catch {
127-
setMessageBudget('redirection not working');
128-
}
129-
}}
130-
budget={budget}
131-
/>
132-
))}
133-
</div>
134-
<SeeMoreButton onClick={handleSeeMore}> {'See More'}</SeeMoreButton>
135105

136-
{messageBudget ? (
137-
<div className='mb-4 text-sm font-medium text-red-600'>
138-
{messageBudget}
106+
<div className='mb-8 w-full text-center text-xl font-medium text-teal-800'>
107+
{'STAFF'}
139108
</div>
140-
) : null}
141-
</div>
109+
<div className='grid grid-cols-2 gap-4'>
110+
{sortedStaff.slice(0, visibleCount).map((staff) => (
111+
<StaffCardHire
112+
key={staff.id}
113+
staff={staff}
114+
onHire={async () => {
115+
if (labelId === undefined) {
116+
setMessageBudget('Label or budget info not loaded yet.');
117+
return;
118+
}
119+
try {
120+
void handleStaffArtist(
121+
staff.id,
122+
staff.price,
123+
labelId,
124+
budget,
125+
);
126+
await navigate('/main-menu');
127+
} catch {
128+
setMessageBudget('redirection not working');
129+
}
130+
}}
131+
budget={budget}
132+
/>
133+
))}
134+
</div>
135+
<SeeMoreButton onClick={handleSeeMore}> {'See More'}</SeeMoreButton>
136+
137+
{messageBudget ? (
138+
<div className='mb-4 text-sm font-medium text-red-600'>
139+
{messageBudget}
140+
</div>
141+
) : null}
142+
</div>
143+
</>
142144
);
143145
}

packages/shared/src/types/database.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ export interface Milestones {
125125
value: number;
126126
}
127127

128+
export interface Price {
129+
id: Generated<number>;
130+
price: number | null;
131+
}
132+
128133
export interface Singles {
129134
artists_hired_id: number;
130135
exp_value: number;
@@ -193,6 +198,7 @@ export interface DB {
193198
logos: Logos;
194199
marketing: Marketing;
195200
milestones: Milestones;
201+
price: Price;
196202
singles: Singles;
197203
singles_albums: SinglesAlbums;
198204
singles_marketing: SinglesMarketing;

0 commit comments

Comments
 (0)