Skip to content
Open
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
20 changes: 10 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 21 additions & 18 deletions src/components/molecules/LoginForm/LoginForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@ import { useState } from 'react';
import { zodResolver } from '@hookform/resolvers/zod';
import Link from 'next/link';
import { useRouter, useSearchParams } from 'next/navigation';
import { FieldError, FieldValues, FormProvider, useForm, useFormContext } from 'react-hook-form';
import {
FormProvider,
useForm,
useFormContext,
type FieldError,
type FieldValues
} from 'react-hook-form';

import { Button } from '@/components/atoms';
import { Alert } from '@/components/atoms/Alert/Alert';
import { LabeledInput } from '@/components/cells';
import { login } from '@/lib/data/customer';
import { login, transferCard } from '@/lib/data/customer';
import { toast } from '@/lib/helpers/toast';

import { LoginFormData, loginFormSchema } from './schema';
import { loginFormSchema, type LoginFormData } from './schema';

export const LoginForm = () => {
const methods = useForm<LoginFormData>({
Expand All @@ -38,6 +44,7 @@ const Form = () => {
register,
formState: { errors, isSubmitting }
} = useFormContext();

const router = useRouter();
const searchParams = useSearchParams();
const isSessionExpired = searchParams.get('sessionExpired') === 'true';
Expand All @@ -48,24 +55,17 @@ const Form = () => {
formData.append('email', data.email);
formData.append('password', data.password);

const res = await login(formData);
if (res) {
// Temporary solution. API returns 200 code in case of auth error. To change when API is updated.
const isCredentialsError =
res.toLowerCase().includes('invalid email or password') ||
res.toLowerCase().includes('unauthorized') ||
res.toLowerCase().includes('incorrect') ||
res.toLowerCase().includes('credentials');

setIsAuthError(isCredentialsError);
try {
await login(formData);

const errorMessage = isCredentialsError ? 'Incorrect email or password' : res;
router.push('/user');
await transferCard();
} catch (err) {
const message = err instanceof Error ? err.message : 'An error occurred. Please try again.';
toast.error({ title: message });

toast.error({ title: errorMessage || 'An error occurred. Please try again.' });
return;
}
setIsAuthError(false);
router.push('/user');
};

const clearApiError = () => {
Expand Down Expand Up @@ -123,7 +123,10 @@ const Form = () => {
/>
</div>

<Link href="/user/forgot-password" className="block text-right label-md uppercase text-action-on-secondary mt-4">
<Link
href="/user/forgot-password"
className="label-md mt-4 block text-right uppercase text-action-on-secondary"
>
Forgot your password?
</Link>

Expand Down
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
"use client"
'use client';

import { Button } from "@/components/atoms"
import { BinIcon } from "@/icons"
import { HttpTypes } from '@medusajs/types';
import { Text } from '@medusajs/ui';

import { convertToLocale } from "@/lib/helpers/money"
import { HttpTypes } from "@medusajs/types"
import { Text } from "@medusajs/ui"
import { Button } from '@/components/atoms';
import { BinIcon } from '@/icons';
import { convertToLocale } from '@/lib/helpers/money';

export const CartShippingMethodRow = ({
method,
currency_code,
onRemoveShippingMethod,
onRemoveShippingMethod
}: {
method: HttpTypes.StoreCartShippingMethod
currency_code: string
onRemoveShippingMethod: (methodId: string) => void
method: HttpTypes.StoreCartShippingMethod;
currency_code: string;
onRemoveShippingMethod: (methodId: string) => void;
}) => {
return (
<div className="mb-4 border rounded-md p-4 flex items-center justify-between">
<div className="mb-4 flex items-center justify-between rounded-md border p-4">
<div>
<Text className="txt-medium-plus text-ui-fg-base mb-1">Method</Text>
<Text className="txt-medium text-ui-fg-subtle">
{method?.name}{" "}
{method?.name}{' '}
{convertToLocale({
amount: method?.amount!,
currency_code: currency_code,
currency_code: currency_code
})}
</Text>
</div>
Expand All @@ -38,5 +38,5 @@ export const CartShippingMethodRow = ({
<BinIcon size={16} />
</Button>
</div>
)
}
);
};
61 changes: 39 additions & 22 deletions src/lib/data/customer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
'use server';


import { HttpTypes } from '@medusajs/types';
import { revalidateTag } from 'next/cache';
import { redirect } from 'next/navigation';
Expand All @@ -13,33 +12,34 @@ import {
getCartId,
removeAuthToken,
removeCartId,
setAuthToken,
} from "./cookies"
setAuthToken
} from './cookies';

export const retrieveCustomer = async (): Promise<HttpTypes.StoreCustomer | null> => {
const authHeaders = await getAuthHeaders()
if (!authHeaders) return null
const authHeaders = await getAuthHeaders();
if (!authHeaders) return null;

const headers = {
...authHeaders,
}
...authHeaders
};

const next = {
...(await getCacheOptions("customers")),
}
...(await getCacheOptions('customers'))
};

return await sdk.client.fetch<{ customer: HttpTypes.StoreCustomer }>(`/store/customers/me`, {
method: "GET",
return await sdk.client
.fetch<{ customer: HttpTypes.StoreCustomer }>(`/store/customers/me`, {
method: 'GET',
query: {
fields: "*orders",
fields: '*orders'
},
headers,
next,
cache: "force-cache"
cache: 'force-cache'
})
.then(({ customer }) => customer ?? null)
.catch(() => null)
}
.catch(() => null);
};

export const updateCustomer = async (body: HttpTypes.StoreUpdateCustomer) => {
const headers = {
Expand Down Expand Up @@ -109,15 +109,32 @@ export async function login(formData: FormData) {
const password = formData.get('password') as string;

try {
await sdk.auth.login('customer', 'emailpass', { email, password }).then(async token => {
await setAuthToken(token as string);
const customerCacheTag = await getCacheTag('customers');
revalidateTag(customerCacheTag);
});
} catch (error: any) {
return error.toString();
const token = await sdk.auth.login('customer', 'emailpass', { email, password });
await setAuthToken(token as string);
const customerCacheTag = await getCacheTag('customers');
revalidateTag(customerCacheTag);
} catch (error: unknown) {
const err = error as { status?: number; response?: { status?: number } };
const status = err.status || err.response?.status;

switch (status) {
case 401:
throw new Error('Invalid email or password. Please try again.');
case 404:
throw new Error('Account not found. Please check your email address.');
case 429:
throw new Error('Too many login attempts. Please try again later.');
case 500:
case 502:
case 503:
throw new Error('Server error. Please try again later.');
default:
throw new Error('Unable to log in. Please try again.');
}
}
}

export async function transferCard() {
try {
await transferCart();
} catch (error: any) {
Expand Down
Loading