Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions client/src/graphql/profile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { gql, type TypedDocumentNode } from '@apollo/client';
import type { Recipe } from '../types/recipe';

// oppskriftene innlogget bruker har laget
export const MY_RECIPES: TypedDocumentNode<{ myRecipes: Recipe[] }> = gql`
query MyRecipes {
myRecipes {
id
imageUrl
title
prepTimeMinutes
servings
}
}
`;
37 changes: 25 additions & 12 deletions client/src/routes/ProfilePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { Link, useNavigate } from 'react-router';
import { Button } from '../components/ui/Button';
import { PreferencesForm } from '../components/profile/PreferencesForm';
import { useCurrentUser } from '../lib/useCurrentUser';
import { useQuery } from '@apollo/client/react';
import { RecipeList } from '../components/recipe/RecipeList';
import { MY_RECIPES } from '../graphql/profile';

type Tab = 'preferences' | 'favorites' | 'shared' | 'sharedWithMe';
type RecipeTab = Exclude<Tab, 'preferences'>;
Expand Down Expand Up @@ -37,10 +40,16 @@ export default function ProfilePage() {
const navigate = useNavigate();
const [activeTab, setActiveTab] = useState<Tab>('preferences');

// oppskriftene brukeren har laget og den henter på nytt hver gang siden åpnes på nytt
const { data: myRecipesData } = useQuery(MY_RECIPES, {
fetchPolicy: 'cache-and-network',
});

// RequireAuth sørger for at user finnes
if (!user) return null;

const isGuest = user.authProvider === 'GUEST';
const myRecipes = myRecipesData?.myRecipes ?? [];

// på desktop vises preferanser alltid til venstre, så høyre side viser favoritter i stedet
const desktopTab: RecipeTab =
Expand Down Expand Up @@ -80,7 +89,7 @@ export default function ProfilePage() {
{/* TODO: hent ekte tall fra backend */}
<ul className="mt-5 flex flex-wrap gap-x-6 gap-y-3">
{[
{ count: 0, label: 'mine oppskrifter' },
{ count: myRecipes.length, label: 'mine oppskrifter' },
{ count: 0, label: 'favoritter' },
{ count: 0, label: 'delte' },
{ count: 0, label: 'delt med deg' },
Expand Down Expand Up @@ -199,17 +208,21 @@ export default function ProfilePage() {
))}
</div>

<section className="rounded-large border border-dashed border-peach p-8 text-center">
<p>{RECIPE_TABS[desktopTab].empty}</p>
{desktopTab === 'favorites' && (
<Link
to="/"
className={`mt-3 inline-block text-primary underline ${FOCUS_RING}`}
>
Utforsk oppskrifter
</Link>
)}
</section>
{desktopTab === 'shared' && myRecipes.length > 0 ? (
<RecipeList recipes={myRecipes} />
) : (
<section className="rounded-large border border-dashed border-peach p-8 text-center">
<p>{RECIPE_TABS[desktopTab].empty}</p>
{desktopTab === 'favorites' && (
<Link
to="/"
className={`mt-3 inline-block text-primary underline ${FOCUS_RING}`}
>
Utforsk oppskrifter
</Link>
)}
</section>
)}
</div>
</div>
);
Expand Down
2 changes: 1 addition & 1 deletion client/src/routes/RegisterPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export default function RegisterPage() {
</Field>

{error && (
<p role="alert" className="font-bold text-primary">
<p role="alert" className="font-bold text-primary wrap-anywhere">
{error}
</p>
)}
Expand Down
2 changes: 1 addition & 1 deletion client/src/routes/TestUserLoginPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export default function TestUserLoginPage() {
</Field>

{error && (
<p role="alert" className="font-bold text-primary">
<p role="alert" className="font-bold text-primary wrap-anywhere">
{error}
</p>
)}
Expand Down
12 changes: 10 additions & 2 deletions server/src/schema/resolvers/recipe.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { prisma } from '../../db/client';
import { GraphQLError } from 'graphql';
import type { Context } from '../../auth/session';

export const recipeResolvers = {
Query: {
Expand All @@ -24,13 +26,19 @@ export const recipeResolvers = {
},
},
Mutation: {
createRecipe: async (_: unknown, args: { input: any }) => {
createRecipe: async (_: unknown, args: { input: any }, context: Context) => {
// gjøre sånn at bare innloggede brukere og gjestebrukere kan lage oppskrift
if (!context.userId) {
throw new GraphQLError('Du må være logget inn for å lage oppskrift.', {
extensions: { code: 'UNAUTHENTICATED' },
});
}
const { ingredients, steps, tagNames, ...rest } = args.input;
return prisma.recipe.create({
data: {
...rest,
status: 'PUBLISHED',
authorId: 'dev-user', // bytt ut når Person 2 har auth klart
authorId: context.userId,
ingredients: { create: ingredients },
steps: { create: steps },
tags: tagNames
Expand Down
9 changes: 9 additions & 0 deletions server/src/schema/resolvers/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@ export const userResolvers = {
if (!context.userId) return null;
return prisma.user.findUnique({ where: { id: context.userId } });
},
// oppskriftenen innlogget bruker har laget, der nyest vises først
myRecipes: async (_: unknown, __: unknown, context: Context) => {
if (!context.userId) return [];
return prisma.recipe.findMany({
where: { authorId: context.userId },
orderBy: { createdAt: 'desc' },
include: { ingredients: true, steps: true, tags: true },
});
},
},

Mutation: {
Expand Down
2 changes: 2 additions & 0 deletions server/src/schema/typeDefs/user.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ type User {
extend type Query {
# innlogget bruker og null hvis ingen er logget inn
me: User
# oppskrifter innlogget bruker har laget
myRecipes: [Recipe!]!
}

extend type Mutation {
Expand Down