Add books feature

This commit is contained in:
MartinBraquet
2025-08-11 17:38:26 +02:00
parent 131cb0ff79
commit 078893f7d1
11 changed files with 150 additions and 27 deletions

View File

@@ -1,5 +1,5 @@
import { prisma } from "@/lib/server/prisma";
import { NextResponse } from "next/server";
import {prisma} from "@/lib/server/prisma";
import {NextResponse} from "next/server";
export async function GET() {
try {
@@ -28,6 +28,17 @@ export async function GET() {
cacheStrategy: cacheStrategy,
});
const books = await prisma.book.findMany({
select: {
id: true,
name: true,
},
orderBy: {
name: 'asc'
},
cacheStrategy: cacheStrategy,
});
const causeAreas = await prisma.causeArea.findMany({
select: {
id: true,
@@ -50,12 +61,12 @@ export async function GET() {
cacheStrategy: cacheStrategy,
});
return NextResponse.json({ interests, coreValues, causeAreas, connections });
return NextResponse.json({interests, coreValues, books, causeAreas, connections});
} catch (error) {
console.error('Error fetching interests:', error);
return NextResponse.json(
{ error: "Failed to fetch interests" },
{ status: 500 }
{error: "Failed to fetch interests"},
{status: 500}
);
}
}

View File

@@ -12,6 +12,7 @@ export async function GET(request: Request) {
const maxIntroversion = url.searchParams.get("maxIntroversion");
const interests = url.searchParams.get("interests")?.split(",").filter(Boolean) || [];
const coreValues = url.searchParams.get("coreValues")?.split(",").filter(Boolean) || [];
const books = url.searchParams.get("books")?.split(",").filter(Boolean) || [];
const causeAreas = url.searchParams.get("causeAreas")?.split(",").filter(Boolean) || [];
const connections = url.searchParams.get("connections")?.split(",").filter(Boolean) || [];
const searchQueries = url.searchParams.get("searchQuery")?.split(",").map(q => q.trim()).filter(Boolean) || [];
@@ -116,6 +117,22 @@ export async function GET(request: Request) {
];
}
// AND
if (books.length > 0) {
where.profile.AND = [
...where.profile.AND,
...books.map((name) => ({
books: {
some: {
value: {
name: name,
},
},
},
})),
];
}
if (causeAreas.length > 0) {
where.profile.AND = [
...where.profile.AND,
@@ -194,6 +211,17 @@ export async function GET(request: Request) {
},
},
},
{
profile: {
books: {
some: {
value: {
name: {contains: query, mode: "insensitive"},
},
},
},
},
},
{
profile: {
causeAreas: {
@@ -259,6 +287,7 @@ export async function GET(request: Request) {
include: {
intellectualInterests: {include: {interest: true}},
coreValues: {include: {value: true}},
books: {include: {value: true}},
causeAreas: {include: {causeArea: true}},
desiredConnections: {include: {connection: true}},
promptAnswers: true,

View File

@@ -14,8 +14,9 @@ export async function POST(req: Request) {
}
const data = await req.json();
const {profile, image, name, interests = [], connections = [], coreValues = [], causeAreas = []} = data;
const {profile, image, name, interests = [], connections = [], coreValues = [], books = [], causeAreas = []} = data;
console.log('books: ', books)
Object.keys(profile).forEach(key => {
if (profile[key] === '' || !profile[key]) {
delete profile[key];
@@ -71,6 +72,8 @@ export async function POST(req: Request) {
profileConnection: prisma.profileConnection,
value: prisma.value,
profileValue: prisma.profileValue,
book: prisma.book,
profileBook: prisma.profileBook,
causeArea: prisma.causeArea,
profileCauseArea: prisma.profileCauseArea,
} as const;
@@ -79,7 +82,7 @@ export async function POST(req: Request) {
async function handleFeatures(features: any, attribute: ModelKey, profileAttribute: string, idName: string) {
// Add new features
if (features.length > 0 && updatedUser.profile) {
if (features !== null && updatedUser.profile) {
// First, find or create all features
console.log('profile', profileAttribute, profileAttribute);
const operations = features.map((feat: { id?: string; name: string }) =>
@@ -95,25 +98,31 @@ export async function POST(req: Request) {
// Get the IDs of all created/updated features
const ids = createdFeatures.map(v => v.id);
// First, remove all existing interests for this profile
await modelMap[profileAttribute].deleteMany({
where: {profileId: updatedUser.profile.id},
});
const profileId = updatedUser.profile.id;
console.log('profile ID:', profileId);
// Then, create new connections
// First, remove all existing features for this profile
const res = await modelMap[profileAttribute].deleteMany({
where: {profileId: profileId},
});
console.log('deleted profile:', profileAttribute, res);
// Then, create new features
if (ids.length > 0) {
await modelMap[profileAttribute].createMany({
const create_res =await modelMap[profileAttribute].createMany({
data: ids.map(id => ({
profileId: updatedUser.profile!.id,
profileId: profileId,
[idName]: id,
})),
skipDuplicates: true,
});
console.log('created many:', profileAttribute, create_res);
}
}
}
await handleFeatures(interests, 'interest', 'profileInterest', 'interestId')
await handleFeatures(books, 'book', 'profileBook', 'valueId')
await handleFeatures(connections, 'connection', 'profileConnection', 'connectionId')
await handleFeatures(coreValues, 'value', 'profileValue', 'valueId')
await handleFeatures(causeAreas, 'causeArea', 'profileCauseArea', 'causeAreaId')

View File

@@ -56,7 +56,7 @@ function RegisterComponent() {
const router = useRouter();
const {data: session, update} = useSession();
const featureNames = ['interests', 'coreValues', 'description', 'connections', 'causeAreas'];
const featureNames = ['interests', 'coreValues', 'description', 'connections', 'causeAreas', 'books'];
const [showMoreInfo, _setShowMoreInfo] = useState(() =>
Object.fromEntries(featureNames.map((id) => [id, false]))
@@ -141,6 +141,7 @@ function RegisterComponent() {
setSelFeat('coreValues', 'coreValues', 'value')
setSelFeat('connections', 'desiredConnections', 'connection')
setSelFeat('causeAreas', 'causeAreas', 'causeArea')
setSelFeat('books', 'books', 'value')
setImages([])
setKeys(profile?.images)
@@ -309,10 +310,11 @@ function RegisterComponent() {
...(key && {image: key}),
...(name && {name}),
};
for (const name of ['interests', 'connections', 'coreValues', 'causeAreas']) {
for (const name of ['books', 'interests', 'connections', 'coreValues', 'causeAreas']) {
// if (!selectedFeatures[name].size) continue;
data[name] = Array.from(selectedFeatures[name]).map(id => ({
id: id.startsWith('new-') ? undefined : id,
name: allFeatures[name].find(i => i.id === id)?.name || id.replace('new-', '')
name: allFeatures[name].find(i => i.id === id)?.name
}));
}
console.log('data', data)
@@ -416,6 +418,20 @@ function RegisterComponent() {
</p>
</>
},
{
id: 'books', title: 'Works to discuss', allowAdd: true,
content: <>
<p className="mt-2">
List the works (books, articles, essays, reports, etc.) you would like to bring up.
For each work, include the exact title (as it appears on the cover), the
authors full name, and, if necessary, the edition or publication year. For example: <i>Peter Singer - Animal
Liberation</i>. If you want to focus on specific
chapters, themes, or questions, note them in your descriptionit helps keep the discussion targeted. Dont just write
something by Orwell or that new mystery; vague entries waste time and make it harder for others to find
the right work. Be explicit so everyone is literally on the same page!
</p>
</>
},
// {
// id: 'causeAreas', title: 'Cause Areas', allowAdd: true,
// content: <>

View File

@@ -31,6 +31,7 @@ export const dropdownConfig: { id: DropdownKey, name: string }[] = [
{id: "connections", name: "Connection Type"},
{id: "coreValues", name: "Values"},
{id: "interests", name: "Interests"},
{id: "books", name: "Works"},
// {id: "causeAreas", name: "Cause Areas"},
]

View File

@@ -20,6 +20,7 @@ const initialState = {
maxIntroversion: null as number | null,
interests: [] as string[],
coreValues: [] as string[],
books: [] as string[],
causeAreas: [] as string[],
connections: [] as string[],
searchQuery: '',
@@ -33,6 +34,7 @@ type ProfileFilters = {
minIntroversion: number | null;
maxIntroversion: number | null;
interests: string[];
books: string[];
coreValues: string[];
causeAreas: string[];
connections: string[];
@@ -327,6 +329,18 @@ export default function ProfilePage() {
</div>
)}
</div>
<div className="mt-4 space-y-2 flex-grow">
{user.profile.books?.length > 0 && (
<div className="flex flex-wrap gap-1">
{user.profile.books.slice(0, 6).map(({value}) => (
<span key={value?.id}
className="inline-block text-xs px-2 py-1 bg-blue-50 text-blue-700 dark:text-white dark:bg-gray-700 rounded-full">
{value?.name}
</span>
))}
</div>
)}
</div>
</div>
</Link>
))}