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: 14 additions & 1 deletion client/src/components/layout/Layout.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,26 @@
import { Outlet } from 'react-router';
import { Outlet, useLocation } from 'react-router';
import { useEffect } from 'react';
import Header from './Header';
import { BottomNav } from './BottomNav';
import { MotionConfig } from 'motion/react';

// starter øverst på siden når man går til en ny side
function ScrollToTop() {
const { pathname } = useLocation();

useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);

return null;
}

// felles ramme for alle sider
export default function Layout() {
return (
// gir mulighet for bruker å skru av animasjoner
<MotionConfig reducedMotion="user">
<ScrollToTop />
<div className="min-h-screen bg-background text-text">
<Header />
{/* ekstra plass nederst på mobil så bunnmenyen ikke dekker innholdet */}
Expand Down
7 changes: 7 additions & 0 deletions client/src/components/layout/UserLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@ import PersonOutlinedIcon from '@mui/icons-material/PersonOutlined';
import PersonIcon from '@mui/icons-material/Person';
import { useCurrentUser } from '../../lib/useCurrentUser';

// glir til toppen men hopper rett opp hvis animasjoner er skrudd av
function scrollToTop() {
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
window.scrollTo({ top: 0, behavior: reduce ? 'auto' : 'smooth' });
}

// brukerikonet går til min side eller til innlogging
export function UserLink() {
const { user } = useCurrentUser();
Expand All @@ -11,6 +17,7 @@ export function UserLink() {
<NavLink
to={user ? '/profile' : '/login'}
aria-label={user ? 'Min side' : 'Logg inn'}
onClick={scrollToTop}
className={({ isActive }) =>
`flex text-4xl transition-colors focus-visible:outline-2 focus-visible:outline-offset-4 focus-visible:outline-pink-light ${
isActive ? 'text-primary' : 'text-primary/80 hover:text-primary'
Expand Down
14 changes: 8 additions & 6 deletions client/src/lib/AuthProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { type ReactNode } from 'react';
import { CombinedGraphQLErrors } from '@apollo/client';
import { useMutation, useQuery } from '@apollo/client/react';
import { useMutation, useQuery, useApolloClient } from '@apollo/client/react';
import type { User } from '../types/user';
import { AuthContext } from './authContext';
import {
Expand All @@ -23,7 +23,9 @@ type AuthProviderProps = { children: ReactNode };

export function AuthProvider({ children }: AuthProviderProps) {
// spør serveren hvem som er logget inn
const { data, loading, refetch } = useQuery(ME);
const { data, loading } = useQuery(ME);
// tømmer cachen når bruker byttes
const client = useApolloClient();
const [loginMutation] = useMutation(LOGIN);
const [registerMutation] = useMutation(REGISTER);
const [logoutMutation] = useMutation(LOGOUT);
Expand All @@ -38,7 +40,7 @@ export function AuthProvider({ children }: AuthProviderProps) {
const continueAsGuest = async () => {
try {
await guestMutation();
await refetch();
await client.resetStore();
return null;
} catch (error) {
return getErrorMessage(error);
Expand All @@ -49,7 +51,7 @@ export function AuthProvider({ children }: AuthProviderProps) {
const login = async (username: string, password: string) => {
try {
await loginMutation({ variables: { username, password } });
await refetch();
await client.resetStore();
return null;
} catch (error) {
return getErrorMessage(error);
Expand All @@ -60,7 +62,7 @@ export function AuthProvider({ children }: AuthProviderProps) {
const register = async (username: string, password: string) => {
try {
await registerMutation({ variables: { username, password } });
await refetch();
await client.resetStore();
return null;
} catch (error) {
return getErrorMessage(error);
Expand All @@ -69,7 +71,7 @@ export function AuthProvider({ children }: AuthProviderProps) {

const logout = async () => {
await logoutMutation();
await refetch();
await client.resetStore();
};

return (
Expand Down
3 changes: 2 additions & 1 deletion client/src/routes/ProfilePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,9 @@ export default function ProfilePage() {
</div>

{/* oppskriftsfanene */}
{/* minstehøyde så siden ikke krymper og kaster deg opp når fanen byttes */}
<div
className={`${activeTab === 'preferences' ? 'hidden' : 'block'} md:block`}
className={`${activeTab === 'preferences' ? 'hidden' : 'block'} min-h-screen md:block`}
>
<div
role="tablist"
Expand Down
18 changes: 18 additions & 0 deletions server/src/schema/resolvers/user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,22 @@ async function findOwnRecipe(id: string, userId: string) {
return recipe;
}

// testbrukeren deles av alle som tester så den skal ikke kunne endres passord eller navn
const TEST_USERNAME = 'test';

// stopper endringer på den delte testbrukeren
async function blockTestUser(userId: string) {
const user = await prisma.user.findUnique({ where: { id: userId } });
if (user?.username === TEST_USERNAME) {
throw new GraphQLError(
'Testbrukeren kan ikke endres, lag en egen bruker hvis du ønsker å teste funksjonen.',
{
extensions: { code: 'FORBIDDEN' },
},
);
}
}

// bytter ut alt innhold i en oppskrift
async function replaceRecipe(
id: string,
Expand Down Expand Up @@ -304,6 +320,7 @@ export const userResolvers = {
extensions: { code: 'UNAUTHENTICATED' },
});
}
await blockTestUser(context.userId);

// fjerner mellomrom før og etter navnet
const name = args.name.trim();
Expand All @@ -330,6 +347,7 @@ export const userResolvers = {
extensions: { code: 'UNAUTHENTICATED' },
});
}
await blockTestUser(context.userId);

const user = await prisma.user.findUnique({
where: { id: context.userId },
Expand Down