From c288c747f81031045c3b9a5e78aa61bd5761032c Mon Sep 17 00:00:00 2001
From: MartinBraquet
Date: Sun, 3 Aug 2025 00:19:37 +0200
Subject: [PATCH] Present existing prompts
---
app/api/profiles/prompts/route.ts | 26 ++++++
app/api/user/update-profile/route.ts | 15 ++--
app/complete-profile/page.tsx | 114 ++++++++++++++++-----------
components/ui/PromptAnswer.tsx | 46 ++++++-----
lib/client/profile.tsx | 2 +-
5 files changed, 131 insertions(+), 72 deletions(-)
create mode 100644 app/api/profiles/prompts/route.ts
diff --git a/app/api/profiles/prompts/route.ts b/app/api/profiles/prompts/route.ts
new file mode 100644
index 00000000..4bbb6a25
--- /dev/null
+++ b/app/api/profiles/prompts/route.ts
@@ -0,0 +1,26 @@
+import { prisma } from "@/lib/server/prisma";
+import { NextResponse } from "next/server";
+
+export async function GET() {
+ try {
+ let data = await prisma.promptAnswer.findMany({
+ select: {
+ prompt: true,
+ },
+ distinct: ['prompt'],
+ });
+
+ const uniquePrompts = data.map((prompt) => prompt.prompt);
+
+ return NextResponse.json({ uniquePrompts });
+ } catch (error) {
+ console.error('Error fetching prompts:', error);
+ return NextResponse.json(
+ { error: "Failed to fetch prompts" },
+ { status: 500 }
+ );
+ }
+}
+
+// This ensures the route is not cached
+export const dynamic = 'force-dynamic';
diff --git a/app/api/user/update-profile/route.ts b/app/api/user/update-profile/route.ts
index ef5e36b7..548fa8e2 100644
--- a/app/api/user/update-profile/route.ts
+++ b/app/api/user/update-profile/route.ts
@@ -35,12 +35,15 @@ export async function POST(req: Request) {
});
console.log('profileData:', profileData);
- const deleted = await prisma.promptAnswer.deleteMany({
- where: {
- profileId: profileData?.id,
- },
- });
- console.log('Deleted prompt answers:', deleted);
+ const profileId = profileData?.id;
+ if (profileId) {
+ const deleted = await prisma.promptAnswer.deleteMany({
+ where: {
+ profileId: profileData?.id,
+ },
+ });
+ console.log('Deleted prompt answers:', deleted);
+ }
}
// First, update/create the profile
diff --git a/app/complete-profile/page.tsx b/app/complete-profile/page.tsx
index 89feabaa..dd92aa43 100644
--- a/app/complete-profile/page.tsx
+++ b/app/complete-profile/page.tsx
@@ -31,6 +31,7 @@ function RegisterComponent() {
const [location, setLocation] = useState('');
const [name, setName] = useState('');
const [gender, setGender] = useState('');
+ const [promptOptions, setPromptOptions] = useState([]);
const [age, setAge] = useState(null);
const [introversion, setIntroversion] = useState(null);
const [personalityType, setPersonalityType] = useState('');
@@ -48,7 +49,7 @@ function RegisterComponent() {
const router = useRouter();
const {data: session, update} = useSession();
- const hooks = Object.fromEntries(['interests', 'coreValues', 'description', 'connections'].map((id) => {
+ const hooks = Object.fromEntries(['interests', 'coreValues', 'description', 'connections', 'causeAreas'].map((id) => {
const [showMoreInfo, setShowMoreInfo] = useState(false);
const [newFeature, setNewFeature] = useState('');
const [allFeatures, setAllFeatures] = useState<{ id: string, name: string }[]>([]);
@@ -73,7 +74,7 @@ function RegisterComponent() {
const id = session?.user.id
- console.log(session)
+ // console.log(session)
// Fetch user profile data
useEffect(() => {
@@ -114,6 +115,7 @@ function RegisterComponent() {
setSelectedFeatures('interests', 'intellectualInterests', 'interest')
setSelectedFeatures('coreValues', 'coreValues', 'value')
setSelectedFeatures('connections', 'desiredConnections', 'connection')
+ setSelectedFeatures('causeAreas', 'causeAreas', 'causeArea')
setImages([])
setKeys(profile?.images)
@@ -134,38 +136,56 @@ function RegisterComponent() {
fetchUserProfile();
}, [session]);
- // Load existing interests and set up click-outside handler
- for (const id of ['interests', 'coreValues', 'connections']) {
- useEffect(() => {
- async function fetchFeatures() {
- try {
- const res = await fetch('/api/interests');
- if (res.ok) {
- const data = await res.json();
- hooks[id].setAllFeatures(data[id] || []);
- }
- } catch (error) {
- console.error('Error loading' + id, error);
+ useEffect(() => {
+ async function asyncRun() {
+ try {
+ const res = await fetch('/api/profiles/prompts');
+ if (res.ok) {
+ const data = await res.json();
+ console.log('uniquePrompts', data.uniquePrompts);
+ setPromptOptions(data.uniquePrompts);
}
+ } catch (error) {
+ console.error('Error from /api/prompts:', error);
}
+ }
- fetchFeatures();
+ asyncRun();
- // Close dropdown when clicking outside
- const handleClickOutside = (event: MouseEvent) => {
- const hook = hooks[id];
- const current = hook.dropdownRef.current;
- if (current && !current.contains(event.target as Node)) {
- hook.setShowDropdown(false);
+ }, []);
+
+ // Load existing interests and set up click-outside handler
+ useEffect(() => {
+ async function fetchFeatures() {
+ try {
+ const res = await fetch('/api/interests');
+ if (res.ok) {
+ const data = await res.json();
+ for (const id of ['interests', 'coreValues', 'connections', 'causeAreas']) {
+ hooks[id].setAllFeatures(data[id] || []);
+
+ // Close dropdown when clicking outside
+ const handleClickOutside = (event: MouseEvent) => {
+ const hook = hooks[id];
+ const current = hook.dropdownRef.current;
+ if (current && !current.contains(event.target as Node)) {
+ hook.setShowDropdown(false);
+ }
+ };
+
+ document.addEventListener('mousedown', handleClickOutside);
+ // return () => {
+ // document.removeEventListener('mousedown', handleClickOutside);
+ // };
+ }
}
- };
+ } catch (error) {
+ console.error('Error loading' + id, error);
+ }
+ }
- document.addEventListener('mousedown', handleClickOutside);
- return () => {
- document.removeEventListener('mousedown', handleClickOutside);
- };
- }, []);
- }
+ fetchFeatures();
+ }, []);
if (isLoading) {
return (
@@ -241,7 +261,7 @@ function RegisterComponent() {
setIsSubmitting(true);
setError('');
- const promptAnswersList = Object.entries(promptAnswers).map(([prompt, answer]) => ({ prompt, answer }));
+ const promptAnswersList = Object.entries(promptAnswers).map(([prompt, answer]) => ({prompt, answer}));
console.log('promptAnswersList', promptAnswersList)
console.log('submit image', key);
@@ -373,6 +393,14 @@ function RegisterComponent() {
>
},
+ {
+ id: 'causeAreas', title: 'Cause Areas', allowAdd: true,
+ content: <>
+
+ ...
+
+ >
+ },
]
function getDropdown({id, title, allowAdd, content}: DropdownConfig) {
@@ -477,7 +505,7 @@ function RegisterComponent() {
{(showDropdown || newFeature) && (
+ className="absolute z-10 mt-1 w-full bg-white dark:bg-gray-800 shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm">
{/* New interest option */}
{allowAdd && newFeature && !allFeatures.some(i =>
i.name.toLowerCase() === newFeature.toLowerCase()
@@ -502,7 +530,7 @@ function RegisterComponent() {
.map((interest) => (
{
toggleFeature(interest.id);
setNewFeature('');
@@ -558,12 +586,6 @@ function RegisterComponent() {
>
}
- const prompts = [
- { id: "1", text: "What are your hobbies and interests?" },
- { id: "2", text: "What are you looking for in a partner?" },
- { id: "3", text: "What's your favorite way to spend a weekend?" },
- ]
-
return (
@@ -707,6 +729,7 @@ function RegisterComponent() {
{getDropdown(dropdownConfig[0])}
{getDropdown(dropdownConfig[1])}
{getDropdown(dropdownConfig[2])}
+ {getDropdown(dropdownConfig[3])}
@@ -787,21 +810,18 @@ function RegisterComponent() {
Your core values
Your altruistic values: community engagement, social justice, and other cause areas
Your level of education, hobbies, pets, habits, subcultures, diet, emotional sensitivity, sense
- of
- humor, ambition, organization, pet peeves, non-negotiables
+ of humor, ambition, organization, pet peeves, non-negotiables
Your thinking style, results from evidence-based personality tests (e.g., Big 5)
Your physical and mental health: some traits that rub people the wrong way, triggers, therapy,
- or what
- you are trying to improve
+ or what you are trying to improve
If interested in romantic relationships, your love languages (giving and receiving), timeline,
romantic orientation, family projects, work-life balance, financial goals / habits, career goals,
housing situation (renting vs owning), and whether you would date someone who already has kids
What you would like in your ideal person or connection—where they should be similar or different
- from
- your own description
+ from your own description
Conversation starters or questions
@@ -842,11 +862,15 @@ function RegisterComponent() {
Prompts
+
+ As of now, you can only answer 1 prompt at a time—just save your profile after answering each prompt.
+
{
console.log(e.promptId, e.prompt, e.text);
+ if (!e.prompt) return;
promptAnswers[e.prompt] = e.text;
setPromptAnswers(promptAnswers);
console.log(promptAnswers);
diff --git a/components/ui/PromptAnswer.tsx b/components/ui/PromptAnswer.tsx
index 1ef07463..7126cfc1 100644
--- a/components/ui/PromptAnswer.tsx
+++ b/components/ui/PromptAnswer.tsx
@@ -3,6 +3,7 @@
import {useEffect, useState} from 'react';
import {Textarea} from '@/components/ui/textarea';
import {Select, SelectContent, SelectItem, SelectTrigger, SelectValue,} from '@/components/ui/select';
+import {cons} from "effect/List";
type Prompt = {
id: string;
@@ -16,9 +17,10 @@ type Answer = {
};
interface PromptAnswerProps {
- prompts: Prompt[];
+ prompts: string[];
onAnswerChange: (answer: Answer) => void;
initialAnswer?: string;
+ initialValues?;
initialPromptId?: string;
className?: string;
}
@@ -27,47 +29,51 @@ export function PromptAnswer(
{
prompts,
onAnswerChange,
+ initialValues = null,
initialAnswer = '',
initialPromptId = '',
className = '',
}: PromptAnswerProps
) {
- const [selectedPromptId, setSelectedPromptId] = useState(initialPromptId);
+ // const [selectedPromptId, setSelectedPromptId] = useState(initialPromptId);
const [answer, setAnswer] = useState(initialAnswer);
const [isCustomPrompt, setIsCustomPrompt] = useState(false);
- const [customPrompt, setCustomPrompt] = useState('');
- const idToPrompt = Object.fromEntries(prompts.map(item => [item.id, item.text]));
- console.log('dictPrompts', idToPrompt)
+ const [selectedPrompt, setSelectedPrompt] = useState('');
+ const idToPrompt = Object.fromEntries(prompts.map((item, idx) => [idx, item]));
+ // console.log('dictPrompts', idToPrompt)
useEffect(() => {
if (initialPromptId === 'custom') {
setIsCustomPrompt(true);
- setCustomPrompt(initialAnswer);
+ setSelectedPrompt(initialAnswer);
}
}, [initialPromptId, initialAnswer]);
- const handlePromptChange = (id: string) => {
- if (id === 'custom') {
+ const handlePromptChange = (prompt: string) => {
+ console.log('handlePromptChange', prompt)
+ if (prompt === 'custom') {
setIsCustomPrompt(true);
- setSelectedPromptId('');
- // onAnswerChange({promptId: 'custom', prompt: customPrompt, text: customPrompt});
+ setSelectedPrompt('');
+ // onAnswerChange({promptId: 'custom', prompt: selectedPrompt, text: selectedPrompt});
} else {
setIsCustomPrompt(false);
- setSelectedPromptId(id);
+ setSelectedPrompt(prompt);
// onAnswerChange({promptId: id, prompt: idToPrompt[id], text: answer});
}
+ setAnswer(initialValues[prompt] || '')
};
const handleAnswerChange = (text: string) => {
setAnswer(text);
+ console.log('handleAnswerChange', text)
onAnswerChange({
- promptId: isCustomPrompt ? 'custom' : selectedPromptId,
- prompt: isCustomPrompt ? customPrompt : idToPrompt[selectedPromptId],
+ promptId: '...',
+ prompt: selectedPrompt,
text: text,
});
};
const handleCustomPromptChange = (text: string) => {
- setCustomPrompt(text);
+ setSelectedPrompt(text);
// onAnswerChange({
// promptId: 'custom',
// prompt: text,
@@ -81,14 +87,14 @@ export function PromptAnswer(
Select a prompt
-
+
-
- {prompts.map((prompt) => (
-
- {prompt.text}
+
+ {prompts.map((prompt, idx) => (
+
+ {prompt}
))}
Write your own prompt
@@ -102,7 +108,7 @@ export function PromptAnswer(
Your custom prompt