Present existing prompts

This commit is contained in:
MartinBraquet
2025-08-03 00:19:37 +02:00
parent 6e1e390d43
commit c288c747f8
5 changed files with 131 additions and 72 deletions

View File

@@ -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';

View File

@@ -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

View File

@@ -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<number | null>(null);
const [introversion, setIntroversion] = useState<number | null>(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() {
</p>
</>
},
{
id: 'causeAreas', title: 'Cause Areas', allowAdd: true,
content: <>
<p className="mt-2">
...
</p>
</>
},
]
function getDropdown({id, title, allowAdd, content}: DropdownConfig) {
@@ -477,7 +505,7 @@ function RegisterComponent() {
{(showDropdown || newFeature) && (
<div
className="absolute z-10 mt-1 w-full bg-white dark:bg-gray-900 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">
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) => (
<div
key={interest.id}
className=" cursor-default select-none relative py-2 pl-3 pr-9 hover:bg-blue-50 dark:hover:bg-gray-700"
className="cursor-default select-none relative py-2 pl-3 pr-9 hover:bg-blue-50 dark:hover:bg-gray-700"
onClick={() => {
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 (
<div className="min-h-screen flex items-center justify-center py-12 px-4 sm:px-6 lg:px-8">
<div className="max-w-3xl w-full space-y-8">
@@ -707,6 +729,7 @@ function RegisterComponent() {
{getDropdown(dropdownConfig[0])}
{getDropdown(dropdownConfig[1])}
{getDropdown(dropdownConfig[2])}
{getDropdown(dropdownConfig[3])}
<div>
<label htmlFor="introversion" className={headingStyle}>
@@ -787,21 +810,18 @@ function RegisterComponent() {
<li>Your core values</li>
<li>Your altruistic values: community engagement, social justice, and other cause areas</li>
<li>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
</li>
<li>Your thinking style, results from evidence-based personality tests (e.g., Big 5)</li>
<li>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
</li>
<li>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
</li>
<li>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
</li>
<li>Conversation starters or questions</li>
</ul>
@@ -842,11 +862,15 @@ function RegisterComponent() {
<label htmlFor="contactInfo" className={headingStyle}>
Prompts
</label>
<p className="text-sm italic">
As of now, you can only answer 1 prompt at a time—just save your profile after answering each prompt.
</p>
<PromptAnswer
prompts={prompts}
// initialValues={promptAnswers}
prompts={promptOptions}
initialValues={promptAnswers}
onAnswerChange={(e) => {
console.log(e.promptId, e.prompt, e.text);
if (!e.prompt) return;
promptAnswers[e.prompt] = e.text;
setPromptAnswers(promptAnswers);
console.log(promptAnswers);

View File

@@ -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(
<label className="block text-sm font-medium text-gray-700">
Select a prompt
</label>
<Select value={isCustomPrompt ? 'custom' : selectedPromptId} onValueChange={handlePromptChange}>
<Select value={isCustomPrompt ? 'custom' : selectedPrompt} onValueChange={handlePromptChange}>
<SelectTrigger className="w-full">
<SelectValue placeholder="Choose a prompt..."/>
</SelectTrigger>
<SelectContent>
{prompts.map((prompt) => (
<SelectItem key={prompt.id} value={prompt.id}>
{prompt.text}
<SelectContent className="max-h-60 overflow-auto">
{prompts.map((prompt, idx) => (
<SelectItem key={idx} value={prompt}>
{prompt}
</SelectItem>
))}
<SelectItem value="custom">Write your own prompt</SelectItem>
@@ -102,7 +108,7 @@ export function PromptAnswer(
Your custom prompt
</label>
<Textarea
value={customPrompt}
value={selectedPrompt}
onChange={(e) => handleCustomPromptChange(e.target.value)}
placeholder="Write your own prompt..."
className="min-h-[100px]"

View File

@@ -70,7 +70,7 @@ export function getProfile(url: string, header: any = null) {
const res = await fetch(url);
const data = await res.json();
setUserData(data);
console.log('userData', data);
// console.log('userData', data);
document.title = data.name;
if (data?.image) {
await parseImage(data.image, setImage);