diff --git a/backend/api/src/app.ts b/backend/api/src/app.ts index 1dd2461..6802ec0 100644 --- a/backend/api/src/app.ts +++ b/backend/api/src/app.ts @@ -13,6 +13,7 @@ import {getCompatibleProfilesHandler} from './compatible-profiles' import {createComment} from './create-comment' import {createCompatibilityQuestion} from './create-compatibility-question' import {setCompatibilityAnswer} from './set-compatibility-answer' +import {deleteCompatibilityAnswer} from './delete-compatibility-answer' import {createProfile} from './create-profile' import {createUser} from './create-user' import {getCompatibilityQuestions} from './get-compatibililty-questions' @@ -341,6 +342,7 @@ const handlers: { [k in APIPath]: APIHandler } = { 'hide-comment': hideComment, 'create-compatibility-question': createCompatibilityQuestion, 'set-compatibility-answer': setCompatibilityAnswer, + 'delete-compatibility-answer': deleteCompatibilityAnswer, 'create-vote': createVote, 'vote': vote, 'contact': contact, diff --git a/backend/api/src/delete-compatibility-answer.ts b/backend/api/src/delete-compatibility-answer.ts new file mode 100644 index 0000000..6a9942a --- /dev/null +++ b/backend/api/src/delete-compatibility-answer.ts @@ -0,0 +1,30 @@ +import {APIHandler} from 'api/helpers/endpoint' +import {createSupabaseDirectClient} from 'shared/supabase/init' +import {APIError} from 'common/api/utils' + +export const deleteCompatibilityAnswer: APIHandler<'delete-compatibility-answer'> = async ( + {id}, auth) => { + const pg = createSupabaseDirectClient() + + // Verify user is the answer author + const item = await pg.oneOrNone( + `SELECT * + FROM compatibility_answers + WHERE id = $1 + AND creator_id = $2`, + [id, auth.uid] + ) + + if (!item) { + throw new APIError(404, 'Item not found') + } + + // Delete the answer + await pg.none( + `DELETE + FROM compatibility_answers + WHERE id = $1 + AND creator_id = $2`, + [id, auth.uid] + ) +} diff --git a/common/src/api/schema.ts b/common/src/api/schema.ts index 879c84a..f21a72f 100644 --- a/common/src/api/schema.ts +++ b/common/src/api/schema.ts @@ -295,6 +295,47 @@ export const API = (_apiTypeCheck = { summary: 'Remove the pinned photo from a profile', tag: 'Profiles', }, + 'create-compatibility-question': { + method: 'POST', + authed: true, + rateLimited: true, + returns: {} as any, + props: z.object({ + question: z.string().min(1).max(MAX_COMPATIBILITY_QUESTION_LENGTH), + options: z.record(z.string(), z.number()), + }), + summary: 'Create a new compatibility question with options', + tag: 'Compatibility', + }, + 'set-compatibility-answer': { + method: 'POST', + authed: true, + rateLimited: true, + returns: {} as Row<'compatibility_answers'>, + props: z + .object({ + questionId: z.number(), + multipleChoice: z.number(), + prefChoices: z.array(z.number()), + importance: z.number(), + explanation: z.string().nullable().optional(), + }) + .strict(), + summary: 'Submit or update a compatibility answer', + tag: 'Compatibility', + }, + 'get-profile-answers': { + method: 'GET', + authed: true, + rateLimited: true, + props: z.object({userId: z.string()}).strict(), + returns: {} as { + status: 'success' + answers: Row<'compatibility_answers'>[] + }, + summary: 'Get compatibility answers for a profile', + tag: 'Compatibility', + }, 'get-compatibility-questions': { method: 'GET', authed: true, @@ -310,6 +351,16 @@ export const API = (_apiTypeCheck = { summary: 'Retrieve compatibility questions and stats', tag: 'Compatibility', }, + 'delete-compatibility-answer': { + method: 'POST', + authed: true, + rateLimited: true, + props: z.object({ + id: z.number(), + }), + summary: 'Delete a compatibility question', + tag: 'Compatibility', + }, 'like-profile': { method: 'POST', authed: true, @@ -626,47 +677,6 @@ export const API = (_apiTypeCheck = { // summary: 'Get reactions for a message', // tag: 'Messages', // }, - 'create-compatibility-question': { - method: 'POST', - authed: true, - rateLimited: true, - returns: {} as any, - props: z.object({ - question: z.string().min(1).max(MAX_COMPATIBILITY_QUESTION_LENGTH), - options: z.record(z.string(), z.number()), - }), - summary: 'Create a new compatibility question with options', - tag: 'Compatibility', - }, - 'set-compatibility-answer': { - method: 'POST', - authed: true, - rateLimited: true, - returns: {} as Row<'compatibility_answers'>, - props: z - .object({ - questionId: z.number(), - multipleChoice: z.number(), - prefChoices: z.array(z.number()), - importance: z.number(), - explanation: z.string().nullable().optional(), - }) - .strict(), - summary: 'Submit or update a compatibility answer', - tag: 'Compatibility', - }, - 'get-profile-answers': { - method: 'GET', - authed: true, - rateLimited: true, - props: z.object({userId: z.string()}).strict(), - returns: {} as { - status: 'success' - answers: Row<'compatibility_answers'>[] - }, - summary: 'Get compatibility answers for a profile', - tag: 'Compatibility', - }, 'create-vote': { method: 'POST', authed: true, diff --git a/web/components/answers/answer-compatibility-question-button.tsx b/web/components/answers/answer-compatibility-question-button.tsx index 9f3feff..6e6097c 100644 --- a/web/components/answers/answer-compatibility-question-button.tsx +++ b/web/components/answers/answer-compatibility-question-button.tsx @@ -1,11 +1,12 @@ -import { User } from 'common/user' -import { QuestionWithCountType } from 'web/hooks/use-questions' -import { useState } from 'react' -import { Button } from 'web/components/buttons/button' -import { Col } from 'web/components/layout/col' -import { MODAL_CLASS, Modal } from 'web/components/layout/modal' -import { AnswerCompatibilityQuestionContent } from './answer-compatibility-question-content' +import {User} from 'common/user' +import {QuestionWithCountType} from 'web/hooks/use-questions' +import {useState} from 'react' +import {Button} from 'web/components/buttons/button' +import {Col} from 'web/components/layout/col' +import {Modal, MODAL_CLASS} from 'web/components/layout/modal' +import {AnswerCompatibilityQuestionContent} from './answer-compatibility-question-content' import router from "next/router"; +import Link from "next/link"; export function AnswerCompatibilityQuestionButton(props: { user: User | null | undefined @@ -29,7 +30,7 @@ export function AnswerCompatibilityQuestionButton(props: { return ( <> {size === 'md' ? ( - + ))} + + )} - {comparedProfile && ( + {comparedProfile && isAnswered && ( )} - {isCurrentUser && ( + {isCurrentUser && isAnswered && ( )} + {/*{question.importance_score == 0 &&
Core Question
}*/} { setEditOpen(false) @@ -474,7 +506,7 @@ function CompatibilityAnswerBlock(props: { function CompatibilityDisplay(props: { question: QuestionWithCountType - profile1: Profile + profile1?: Profile profile2: Profile answer1: rowFor<'compatibility_answers'> currentUserIsComparedProfile: boolean @@ -514,7 +546,7 @@ function CompatibilityDisplay(props: { const [open, setOpen] = useState(false) - if (profile1.id === profile2.id) return null + if (!profile1 || profile1.id === profile2.id) return null const showCreateAnswer = (!answer2 || answer2.importance == -1) && diff --git a/web/components/buttons/button.tsx b/web/components/buttons/button.tsx index ee500b0..bfe7428 100644 --- a/web/components/buttons/button.tsx +++ b/web/components/buttons/button.tsx @@ -81,7 +81,7 @@ export const Button = forwardRef(function Button( props: { className?: string size?: SizeType - color?: ColorType + color?: ColorType | null type?: 'button' | 'reset' | 'submit' loading?: boolean } & JSX.IntrinsicElements['button'], @@ -101,7 +101,7 @@ export const Button = forwardRef(function Button( return (