-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add list progress tracking service and endpoint (#115)
* feat: Add list progress tracking service and endpoint * docs: Update CHANGELOG with list progress endpoint
- Loading branch information
1 parent
5cce951
commit 1435240
Showing
6 changed files
with
222 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
import { describe, expect, it } from 'vitest' | ||
import { makeUser } from '@/test/factories/make-user' | ||
import { makeList } from '@/test/factories/make-list' | ||
import { makeListItem } from '@/test/factories/make-list-item' | ||
import { makeUserItem } from '@/test/factories/make-user-item' | ||
import { getListProgressService } from './get-list-progress' | ||
|
||
describe('get list progress', () => { | ||
it('should return zero progress when list has no items', async () => { | ||
const user = await makeUser() | ||
const list = await makeList({ userId: user.id }) | ||
|
||
const sut = await getListProgressService({ | ||
id: list.id, | ||
authenticatedUserId: user.id, | ||
}) | ||
|
||
expect(sut).toEqual({ | ||
total: 0, | ||
completed: 0, | ||
percentage: 0, | ||
}) | ||
}) | ||
|
||
it('should calculate correct progress when user has watched some items', async () => { | ||
const user = await makeUser() | ||
const list = await makeList({ userId: user.id }) | ||
|
||
const listItem1 = await makeListItem({ | ||
listId: list.id, | ||
tmdbId: 123, | ||
mediaType: 'MOVIE', | ||
}) | ||
|
||
await makeListItem({ | ||
listId: list.id, | ||
tmdbId: 456, | ||
mediaType: 'MOVIE', | ||
}) | ||
|
||
await makeUserItem({ | ||
userId: user.id, | ||
tmdbId: listItem1.tmdbId, | ||
mediaType: listItem1.mediaType, | ||
status: 'WATCHED', | ||
}) | ||
|
||
const sut = await getListProgressService({ | ||
id: list.id, | ||
authenticatedUserId: user.id, | ||
}) | ||
|
||
expect(sut).toEqual({ | ||
total: 2, | ||
completed: 1, | ||
percentage: 50, | ||
}) | ||
}) | ||
|
||
it('should calculate 100% progress when user has watched all items', async () => { | ||
const user = await makeUser() | ||
const list = await makeList({ userId: user.id }) | ||
|
||
const listItem1 = await makeListItem({ | ||
listId: list.id, | ||
tmdbId: 123, | ||
mediaType: 'MOVIE', | ||
}) | ||
const listItem2 = await makeListItem({ | ||
listId: list.id, | ||
tmdbId: 456, | ||
mediaType: 'MOVIE', | ||
}) | ||
|
||
await makeUserItem({ | ||
userId: user.id, | ||
tmdbId: listItem1.tmdbId, | ||
mediaType: listItem1.mediaType, | ||
status: 'WATCHED', | ||
}) | ||
await makeUserItem({ | ||
userId: user.id, | ||
tmdbId: listItem2.tmdbId, | ||
mediaType: listItem2.mediaType, | ||
status: 'WATCHED', | ||
}) | ||
|
||
const sut = await getListProgressService({ | ||
id: list.id, | ||
authenticatedUserId: user.id, | ||
}) | ||
|
||
expect(sut).toEqual({ | ||
total: 2, | ||
completed: 2, | ||
percentage: 100, | ||
}) | ||
}) | ||
|
||
it('should ignore user items with different media type', async () => { | ||
const user = await makeUser() | ||
const list = await makeList({ userId: user.id }) | ||
|
||
const listItem = await makeListItem({ | ||
listId: list.id, | ||
tmdbId: 123, | ||
mediaType: 'MOVIE', | ||
}) | ||
|
||
await makeUserItem({ | ||
userId: user.id, | ||
tmdbId: listItem.tmdbId, | ||
mediaType: 'TV_SHOW', | ||
status: 'WATCHED', | ||
}) | ||
|
||
const sut = await getListProgressService({ | ||
id: list.id, | ||
authenticatedUserId: user.id, | ||
}) | ||
|
||
expect(sut).toEqual({ | ||
total: 1, | ||
completed: 0, | ||
percentage: 0, | ||
}) | ||
}) | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import { selectListItems } from '@/db/repositories/list-item-repository' | ||
import { selectAllUserItemsByStatus } from '@/db/repositories/user-item-repository' | ||
|
||
type GetListProgressServiceParams = { | ||
id: string | ||
authenticatedUserId: string | ||
} | ||
|
||
export async function getListProgressService({ | ||
id, | ||
authenticatedUserId, | ||
}: GetListProgressServiceParams) { | ||
const listItems = await selectListItems(id) | ||
if (listItems.length === 0) { | ||
return { | ||
total: 0, | ||
completed: 0, | ||
percentage: 0, | ||
} | ||
} | ||
|
||
const userItems = await selectAllUserItemsByStatus({ | ||
userId: authenticatedUserId, | ||
status: 'WATCHED', | ||
}) | ||
|
||
const watchedItems = listItems.filter(listItem => | ||
userItems.some( | ||
userItem => | ||
userItem.tmdbId === listItem.tmdbId && | ||
userItem.mediaType === listItem.mediaType | ||
) | ||
) | ||
|
||
const percentage = Math.round((watchedItems.length / listItems.length) * 100) | ||
|
||
return { | ||
total: listItems.length, | ||
completed: watchedItems.length, | ||
percentage, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters