Skip to content

Commit

Permalink
feat(Posts): add like feature for posts
Browse files Browse the repository at this point in the history
  • Loading branch information
jkklapp committed Jun 6, 2022
1 parent b511117 commit b761f29
Show file tree
Hide file tree
Showing 9 changed files with 195 additions and 26 deletions.
19 changes: 15 additions & 4 deletions backend/src/posts/controller.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ describe('Controller', () => {
message: 'test',
date: 100000,
userId: '1234',
likes: [],
},
],
remainingMessages: 10,
Expand All @@ -55,6 +56,8 @@ describe('Controller', () => {
message: 'test',
userId: '1234',
userName: 'John Doe',
likes: 0,
likedByMe: false,
},
],
});
Expand All @@ -66,17 +69,22 @@ describe('Controller', () => {
message: 'test',
date: 100000,
userId: '1234',
userName: 'Test',
likes: [],
});
});
it('should return a new post', async () => {
expect(
await c.create({ user: { user_id: '1234' } }, { message: 'test' }),
await c.create(
{ user: { user_id: '1234', name: 'Test' } },
{ message: 'test' },
),
).toEqual({
message: 'test',
date: 100000,
userId: '1234',
userName: 'Test',
likes: 0,
likedByMe: false,
});
});
describe('when the user has reached the max number of posts per day', () => {
Expand Down Expand Up @@ -113,12 +121,15 @@ describe('Controller', () => {
s.toggleLike = jest.fn();
});
it('should add a like in the doc', async () => {
expect(await c.update({ user: { user_id: '1234' } }, '1')).toEqual({
expect(
await c.update({ user: { user_id: '1234' } }, '1', { like: true }),
).toEqual({
message: 'test',
date: 100000,
userId: '1234',
userName: 'Jane Doe',
likes: ['1234'],
likes: 1,
likedByMe: true,
});
});
});
Expand Down
24 changes: 20 additions & 4 deletions backend/src/posts/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Body,
Controller as BaseController,
Get,
HttpCode,
Param,
ParseIntPipe,
Post,
Expand All @@ -15,6 +16,7 @@ import {
ResolvedPostDocument,
NewPostDocument,
PostDocumentResult,
UpdatePostDocument,
} from './document';
import { Service } from './service';
import { FirebaseAuthGuard } from '../firebase/firebase-auth.guard';
Expand All @@ -31,6 +33,8 @@ export class Controller {
@Query('limit', ParseIntPipe) limit: number,
@Query('startAfter') startAfter?: string,
): Promise<PostDocumentResult> {
const { user } = request;
const { user_id: userId } = user;
const { results, nextPageToken } = await this.service.getMultiple(
limit,
startAfter,
Expand All @@ -39,12 +43,12 @@ export class Controller {
for (const p in results) {
resolvedPosts.push({
...results[p],
likes: (results[p].likes || []).length,
likedByMe: (results[p].likes || []).includes(userId),
userName: await getDisplayNameByUserId(results[p].userId),
});
}

const { user } = request;
const { user_id: userId } = user;
const last24hours = Date.now() - 86400000;
const numberPostsCreatedToday = await this.service.countAllforUserByDate(
userId,
Expand Down Expand Up @@ -95,14 +99,23 @@ export class Controller {
);
}

return this.service.create(post.message, userId, userName);
const newPost = await this.service.create(post.message, userId);

return {
...newPost,
likes: newPost.likes.length,
likedByMe: false,
userName,
};
}

@Put('/:id')
@HttpCode(202)
@UseGuards(FirebaseAuthGuard)
public async update(
@Req() request: any,
@Param('id') id: string,
@Body() payload: UpdatePostDocument,
): Promise<ResolvedPostDocument> {
const { user } = request;
const { user_id: userId } = user;
Expand All @@ -112,7 +125,8 @@ export class Controller {
throw new BadRequestException('Post not found');
}

await this.service.toggleLike(id, userId);
const { like: likedByMe } = payload;
await this.service.toggleLike(id, userId, likedByMe);

const post = await this.service.get(id);

Expand All @@ -121,6 +135,8 @@ export class Controller {
return {
...post,
userName,
likes: post.likes.length,
likedByMe,
};
}
}
16 changes: 14 additions & 2 deletions backend/src/posts/document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,22 @@ export class PaginatedResults {
nextPageToken: number | null;
}

export class PostDocumentResult extends PaginatedResults {
export class PostDocumentResult {
results: ResolvedPostDocument[];
nextPageToken: number | null;
remainingMessages: number;
}

export class ResolvedPostDocument extends PostDocument {
export class ResolvedPostDocument {
userName: string;
message: string;
date: number;
userId: string;
id?: string;
likes: number;
likedByMe: boolean;
}

export class UpdatePostDocument {
like: boolean;
}
1 change: 0 additions & 1 deletion backend/src/posts/service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,6 @@ describe('Service', () => {
id: '1',
message: 'test',
userId: '1234',
userName: 'Test',
});
expect(postsCollectionMock.doc).toHaveBeenCalled();
expect(postsCollectionMock.set).toHaveBeenCalledWith({
Expand Down
20 changes: 6 additions & 14 deletions backend/src/posts/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,15 @@ export class Service {
});
}

async toggleLike(id: string, userId: string) {
async toggleLike(id: string, userId: string, like: boolean) {
const docRef = this.postsCollection.doc(id);
return docRef.get().then((postDoc) => {
const post = postDoc.data();
const likes = post.likes || [];
const likeIndex = likes.indexOf(userId);
if (likeIndex === -1) {
likes.push(userId);
} else {
likes.splice(likeIndex, 1);
}
return docRef.update({ likes });
const newLikes = like
? [...likes, userId]
: likes.filter((l) => l !== userId);
return docRef.update({ likes: newLikes });
});
}

Expand Down Expand Up @@ -90,11 +87,7 @@ export class Service {
.then((snapshot) => snapshot.size);
}

async create(
message: string,
userId: string,
userName: string,
): Promise<ResolvedPostDocument> {
async create(message: string, userId: string): Promise<PostDocument> {
const t = dayjs(new Date()).valueOf();
const docRef = this.postsCollection.doc(t.toString());
await docRef.set({
Expand All @@ -110,7 +103,6 @@ export class Service {
return {
...post,
id: docId,
userName,
};
});
}
Expand Down
22 changes: 21 additions & 1 deletion frontend/src/components/Dashboard/Posts.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
>
<div class="flex flex-wrap">
<div>
<small>{{ p.userName }} - {{ date(p.date) }}</small>
<small>{{ p.userName }} · {{ date(p.date) }}</small>
</div>
<div
v-if="!p.id && isPosting"
Expand All @@ -25,6 +25,19 @@
<div>
<span>{{ p.message }}</span>
</div>
<div class="flex flex-wrap place-items-end">
<div class="w-100 mr-auto"></div>
<span class="text-xs text-gray-400">{{ p.likes }}</span
><a href="#" @click.prevent="() => toggleLike(!p.likedByMe, p)"
><LightBulb
:on="p.likedByMe"
:class-names="
p.likedByMe
? 'fill-blue-700 dark:fill-gray-200 w-3 h-3'
: 'fill-gray-300 dark:fill-gray-400 w-3 h-3'
"
/></a>
</div>
</div>
<div class="grid flex-wrap place-items-center">
<button
Expand Down Expand Up @@ -56,8 +69,12 @@
<script>
import { mapGetters } from 'vuex';
import moment from 'moment';
import LightBulb from '../misc/icons/LightBulb';
export default {
components: {
LightBulb,
},
computed: {
...mapGetters({
posts: 'getPosts',
Expand All @@ -78,6 +95,9 @@ export default {
this.$store.dispatch('resetPostsPagination');
this.fetchPosts();
},
toggleLike(like, post) {
this.$store.dispatch('toggleLike', { post, like });
},
},
};
</script>
101 changes: 101 additions & 0 deletions frontend/src/components/misc/icons/LightBulb.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
<template>
<div>
<svg
v-if="!on"
class="w-4 h-4 text-gray-500 dark:text-gray-400"
:class="[[classNames]]"
fill="currentColor"
x="0px"
y="0px"
viewBox="0 0 489.242 489.242"
style="enable-background: new 0 0 489.242 489.242"
xml:space="preserve"
>
<g>
<g>
<path
d="M416.321,171.943c0-97.8-82.2-176.9-181-171.7c-89.5,5.2-160.3,79.1-162.4,168.6c0,44.7,16.6,86.3,45.8,118.6
c47.7,51.1,41.6,110.3,41.6,110.3c0,11.4,9.4,20.8,20.8,20.8h126.9c11.4,0,20.8-9.4,21.8-20.8c0,0-7-57.7,40.6-109.2
C399.621,257.243,416.321,215.643,416.321,171.943z M288.321,377.943h-87.4c-2.1-42.7-20.8-84.3-51-116.5
c-22.9-25-34.3-57.2-34.3-90.5c1-68.7,54.1-124.8,122.8-129c74.9-4.2,137.3,56.2,137.3,130c0,32.3-12.5,64.5-35.4,88.4
C309.121,293.643,290.421,335.243,288.321,377.943z"
/>
<path
d="M281.021,447.643h-73.9c-11.4,0-20.8,9.4-20.8,20.8s9.4,20.8,20.8,20.8h73.9c11.4,0,20.8-9.4,20.8-20.8
C301.821,457.043,292.521,447.643,281.021,447.643z"
/>
</g>
</g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
</svg>
<svg
v-else
class="w-4 h-4 text-gray-500 dark:text-gray-400"
:class="[[classNames]]"
x="0px"
y="0px"
width="417.075px"
height="417.075px"
viewBox="0 0 417.075 417.075"
style="enable-background: new 0 0 417.075 417.075"
xml:space="preserve"
>
<g>
<g>
<path
d="M346.717,131.279C346.717,58.89,284.731,0,208.538,0S70.358,58.891,70.358,131.279c0,50.467,19.548,79.123,38.464,106.849
c15.547,22.779,31.605,46.33,33,77.959H275.34c1.402-31.604,17.43-55.146,32.961-77.938
C327.188,210.436,346.717,181.779,346.717,131.279z"
/>
<path
d="M143.258,368.438c0,9.425,7.641,17.064,17.066,17.064h10.431c3.223,17.95,18.906,31.573,37.783,31.573
c18.876,0,34.56-13.623,37.783-31.573h10.432c9.424,0,17.066-7.641,17.066-17.064v-28.795H143.258V368.438z"
/>
</g>
</g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
<g></g>
</svg>
</div>
</template>
<script>
export default {
props: {
classNames: {
type: String,
default: 'fill-current',
},
on: {
type: Boolean,
default: false,
},
},
};
</script>
14 changes: 14 additions & 0 deletions frontend/src/store/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,18 @@ export default {
}
commit('IS_CREATING_POST', false);
},
async toggleLike({ commit }, { post, like }) {
try {
await apiRequest('PUT', `/posts/${post.id}`, null, {
like,
});
commit('SET_POST_BY_ID', {
...post,
likes: like ? post.likes + 1 : post.likes - 1,
likedByMe: like,
});
} catch ({ response }) {
throw response.data;
}
},
};
Loading

0 comments on commit b761f29

Please sign in to comment.