⚠️ Beta / Test Environment — use card 4242 4242 4242 4242
1 @Injectable()
2 export class ResponsesService {
3 constructor(
4 private readonly db: DatabaseService,
5 private readonly email: EmailService,
6 ) {}
7
8 async create(developerId: string, questionId: string, dto: {
9 blocks: any[];
10 effortEstimate?: string;
11 offerPriceCents?: number;
12 offerTimeMinutes?: number;
13 }) {
14 const existing = await this.db.response.findFirst({
15 where: { developerId, questionId },
16 });
17 if (existing) throw new ConflictException(
18 'You have already responded to this question'
19 );
20
21 const response = await this.db.response.create({
22 data: {
23 questionId, developerId,
24 blocks: dto.blocks,
25 effortEstimate: dto.effortEstimate,
26 offerPriceCents: dto.offerPriceCents,
27 },
28 });
29
30 await this.db.question.update({
31 where: { id: questionId },
32 data: { status: 'LOCKED' },
33 });
34
35 const question = await this.db.question.findUnique({
36 where: { id: questionId }
37 });
38 const thread = await this.db.thread.findUnique({
39 where: { questionId }
40 });
41
42 if (!thread && question) {
43 await this.db.thread.create({
44 data: {
45 userId: question.userId,
46 developerId,
47 questionId,
48 status: 'AWAITING_PAYMENT',
49 devSection: 'NEW_REQUESTS',
50 userSection: 'WAITING_ON_YOU',
51 },
52 });
53 }
54
55 if (question) {
56 const user = await this.db.user.findUnique({
57 where: { id: question.userId }
58 });
59 if (user?.email) {
60 await this.email.sendOfferReceived(user.email, {
61 userName: user.name || 'there',
62 questionTitle: question.title || 'your question',
63 threadUrl: `https://app.popstack.dev/threads/${thread?.id}`,
64 });
65 }
66 }
67
68 return response;
69 }
70 }
71
72 @Controller('questions')
73 @UseGuards(JwtAuthGuard, RolesGuard)
74 export class ResponsesController {
75 constructor(private readonly responses: ResponsesService) {}
76
77 @Post(':id/response')
78 @Roles('DEVELOPER')
79 create(
80 @Param('id') questionId: string,
81 @CurrentUser() dev: any,
82 @Body() dto: any,
83 ) {
84 return this.responses.create(dev.id, questionId, dto);
85 }
86
87 @Get(':id/responses')
88 @Roles('USER')
89 getForQuestion(@Param('id') questionId: string) {
90 return this.responses.getForQuestion(questionId);
91 }
92 }
93
94 @NestModule({
95 controllers: [ResponsesController],
96 providers: [ResponsesService, EmailService],
97 exports: [ResponsesService]
98 })
99 export class ResponsesModule {}
1 @Injectable()
2 export class ResponsesService {
3 constructor(
4 private readonly db: DatabaseService,
5 private readonly email: EmailService,
6 ) {}
7
8 async create(developerId: string, questionId: string, dto: {
9 blocks: any[];
10 effortEstimate?: string;
11 offerPriceCents?: number;
12 offerTimeMinutes?: number;
13 }) {
14 const existing = await this.db.response.findFirst({
15 where: { developerId, questionId },
16 });
17 if (existing) throw new ConflictException(
18 'You have already responded to this question'
19 );
20
21 const response = await this.db.response.create({
22 data: {
23 questionId, developerId,
24 blocks: dto.blocks,
25 effortEstimate: dto.effortEstimate,
26 offerPriceCents: dto.offerPriceCents,
27 },
28 });
29
30 await this.db.question.update({
31 where: { id: questionId },
32 data: { status: 'LOCKED' },
33 });
34
35 const question = await this.db.question.findUnique({
36 where: { id: questionId }
37 });
38 const thread = await this.db.thread.findUnique({
39 where: { questionId }
40 });
41
42 if (!thread && question) {
43 await this.db.thread.create({
44 data: {
45 userId: question.userId,
46 developerId,
47 questionId,
48 status: 'AWAITING_PAYMENT',
49 devSection: 'NEW_REQUESTS',
50 userSection: 'WAITING_ON_YOU',
51 },
52 });
53 }
54
55 if (question) {
56 const user = await this.db.user.findUnique({
57 where: { id: question.userId }
58 });
59 if (user?.email) {
60 await this.email.sendOfferReceived(user.email, {
61 userName: user.name || 'there',
62 questionTitle: question.title || 'your question',
63 threadUrl: `https://app.popstack.dev/threads/${thread?.id}`,
64 });
65 }
66 }
67
68 return response;
69 }
70 }
71
72 @Controller('questions')
73 @UseGuards(JwtAuthGuard, RolesGuard)
74 export class ResponsesController {
75 constructor(private readonly responses: ResponsesService) {}
76
77 @Post(':id/response')
78 @Roles('DEVELOPER')
79 create(
80 @Param('id') questionId: string,
81 @CurrentUser() dev: any,
82 @Body() dto: any,
83 ) {
84 return this.responses.create(dev.id, questionId, dto);
85 }
86
87 @Get(':id/responses')
88 @Roles('USER')
89 getForQuestion(@Param('id') questionId: string) {
90 return this.responses.getForQuestion(questionId);
91 }
92 }
93
94 @NestModule({
95 controllers: [ResponsesController],
96 providers: [ResponsesService, EmailService],
97 exports: [ResponsesService]
98 })
99 export class ResponsesModule {}
1 @Injectable()
2 export class ResponsesService {
3 constructor(
4 private readonly db: DatabaseService,
5 private readonly email: EmailService,
6 ) {}
7
8 async create(developerId: string, questionId: string, dto: {
9 blocks: any[];
10 effortEstimate?: string;
11 offerPriceCents?: number;
12 offerTimeMinutes?: number;
13 }) {
14 const existing = await this.db.response.findFirst({
15 where: { developerId, questionId },
16 });
17 if (existing) throw new ConflictException(
18 'You have already responded to this question'
19 );
20
21 const response = await this.db.response.create({
22 data: {
23 questionId, developerId,
24 blocks: dto.blocks,
25 effortEstimate: dto.effortEstimate,
26 offerPriceCents: dto.offerPriceCents,
27 },
28 });
29
30 await this.db.question.update({
31 where: { id: questionId },
32 data: { status: 'LOCKED' },
33 });
34
35 const question = await this.db.question.findUnique({
36 where: { id: questionId }
37 });
38 const thread = await this.db.thread.findUnique({
39 where: { questionId }
40 });
41
42 if (!thread && question) {
43 await this.db.thread.create({
44 data: {
45 userId: question.userId,
46 developerId,
47 questionId,
48 status: 'AWAITING_PAYMENT',
49 devSection: 'NEW_REQUESTS',
50 userSection: 'WAITING_ON_YOU',
51 },
52 });
53 }
54
55 if (question) {
56 const user = await this.db.user.findUnique({
57 where: { id: question.userId }
58 });
59 if (user?.email) {
60 await this.email.sendOfferReceived(user.email, {
61 userName: user.name || 'there',
62 questionTitle: question.title || 'your question',
63 threadUrl: `https://app.popstack.dev/threads/${thread?.id}`,
64 });
65 }
66 }
67
68 return response;
69 }
70 }
71
72 @Controller('questions')
73 @UseGuards(JwtAuthGuard, RolesGuard)
74 export class ResponsesController {
75 constructor(private readonly responses: ResponsesService) {}
76
77 @Post(':id/response')
78 @Roles('DEVELOPER')
79 create(
80 @Param('id') questionId: string,
81 @CurrentUser() dev: any,
82 @Body() dto: any,
83 ) {
84 return this.responses.create(dev.id, questionId, dto);
85 }
86
87 @Get(':id/responses')
88 @Roles('USER')
89 getForQuestion(@Param('id') questionId: string) {
90 return this.responses.getForQuestion(questionId);
91 }
92 }
93
94 @NestModule({
95 controllers: [ResponsesController],
96 providers: [ResponsesService, EmailService],
97 exports: [ResponsesService]
98 })
99 export class ResponsesModule {}
Loading...