Skip to content

Commit 04658e3

Browse files
committed
feat(cards): implement card sharing and shared card retrieval
1 parent 1630764 commit 04658e3

2 files changed

Lines changed: 98 additions & 2 deletions

File tree

apps/backend/src/routes/cards.ts

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type { CardResponse } from '../services/cardService';
66
import type { Card } from '@devcard/shared';
77
import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
88
import { CardVisibility } from '@prisma/client';
9+
import { request } from 'http';
910

1011
export interface CreateCardBody {
1112
title: string;
@@ -129,7 +130,6 @@ export async function cardRoutes(app: FastifyInstance): Promise<void> {
129130
});
130131

131132
// ─── Set Default Card ───
132-
133133
app.put('/:id/default', async (request: FastifyRequest<{ Params: CardParams }>, reply: FastifyReply): Promise<object | void> => {
134134
const userId = (request.user as { id: string }).id;
135135
const { id } = request.params;
@@ -182,4 +182,48 @@ export async function cardRoutes(app: FastifyInstance): Promise<void> {
182182
handleDbError(error, request, reply)
183183
}
184184
})
185+
186+
//Share card
187+
app.post('/:id/share',async(request: FastifyRequest<{Params: {id: string}}>, reply:FastifyReply) => {
188+
const cardId = request.params.id;
189+
const userId = request.user.id;
190+
191+
try {
192+
const link = await cardService.shareCard(app, userId, cardId);
193+
return reply.status(200).send(link)
194+
} catch (error:any) {
195+
if (error?.code === 'CARD_NOT_FOUND') {
196+
return reply.status(404).send({
197+
error: error.message,
198+
});
199+
}
200+
if (error?.code === 'CARD_PRIVATE') {
201+
return reply.status(403).send({
202+
error: error.message,
203+
});
204+
}
205+
206+
app.log.error(error)
207+
handleDbError(error, request, reply)
208+
}
209+
})
210+
211+
//Get shared card
212+
app.get('/share/:slug', async(request: FastifyRequest<{Params: {slug: string}}>, reply: FastifyReply) => {
213+
const paramsSlug = request.params.slug;
214+
215+
try {
216+
const card = await cardService.getSharedCard(app, paramsSlug)
217+
return reply.status(200).send(card)
218+
} catch (error:any) {
219+
if (error?.code === 'CARD_NOT_FOUND') {
220+
return reply.status(404).send({
221+
error: error.message,
222+
});
223+
}
224+
225+
app.log.error(error)
226+
handleDbError(error, request,reply)
227+
}
228+
})
185229
}

apps/backend/src/services/cardService.ts

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CardVisibility, type Prisma } from '@prisma/client';
1+
import { CardVisibility, Prisma } from '@prisma/client';
22

33
import { generateUniqueSlug } from '../utils/slug';
44

@@ -248,4 +248,56 @@ export async function addPlatFormLinks(app: FastifyInstance, userId: string, id:
248248
platformLinkId
249249
}
250250
})
251+
}
252+
253+
export async function shareCard(app: FastifyInstance, userId:string, id: string){
254+
const card = await app.prisma.card.findFirst({
255+
where:{
256+
id,
257+
userId
258+
}
259+
})
260+
261+
if (!card) {
262+
throw Object.assign(
263+
new Error('Card not found'),
264+
{ code: 'CARD_NOT_FOUND' }
265+
);
266+
}
267+
268+
269+
if(card?.visibility === CardVisibility.PRIVATE){
270+
throw Object.assign(
271+
new Error('Private cards cannot be shared'),
272+
{ code: 'CARD_PRIVATE' }
273+
);
274+
}
275+
276+
return {
277+
shareUrl: `/cards/share/${card.slug}`,
278+
};
279+
}
280+
281+
export async function getSharedCard(app:FastifyInstance, slug:string){
282+
const card = await app.prisma.card.findUnique({
283+
where: {
284+
slug
285+
},
286+
include: {
287+
cardLinks: {
288+
include: {
289+
platformLink: true
290+
}
291+
}
292+
}
293+
})
294+
295+
if(!card){
296+
throw Object.assign(
297+
new Error('Card not found'),
298+
{ code: 'CARD_NOT_FOUND' }
299+
);
300+
}
301+
302+
return card
251303
}

0 commit comments

Comments
 (0)