diff --git a/backend/app/api/dependencies.py b/backend/app/api/dependencies.py index 97ff70f..5d60ce7 100644 --- a/backend/app/api/dependencies.py +++ b/backend/app/api/dependencies.py @@ -5,7 +5,7 @@ from fastapi import Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm from jwt.exceptions import InvalidTokenError from pydantic import ValidationError -from sqlmodel import Session +from sqlmodel import Session, select from app.core import security from app.core.config import settings @@ -19,7 +19,7 @@ reusable_oauth2 = OAuth2PasswordBearer( SessionDep = Annotated[Session, Depends(get_session)] TokenDep = Annotated[str, Depends(reusable_oauth2)] -LoginDep = Annotated[OAuth2PasswordRequestForm, Depends()] +LoginDep = Annotated[OAuth2PasswordRequestForm, Depends(OAuth2PasswordRequestForm)] def get_current_user(session: SessionDep, token: TokenDep) -> User: @@ -33,11 +33,10 @@ def get_current_user(session: SessionDep, token: TokenDep) -> User: status_code=status.HTTP_403_FORBIDDEN, detail="Could not validate credentials", ) - user = session.get(User, {"uuid": token_data.sub}) + stmt = select(User).where(User.uuid == token_data.sub) + user = session.exec(stmt).one_or_none() if not user: raise HTTPException(status_code=404, detail="User not found") - if not user.is_active: - raise HTTPException(status_code=400, detail="Inactive user") return user diff --git a/backend/app/api/routes/login_routes.py b/backend/app/api/routes/login_routes.py index 279c59e..b2ac412 100644 --- a/backend/app/api/routes/login_routes.py +++ b/backend/app/api/routes/login_routes.py @@ -30,7 +30,7 @@ def login_access_token( """ user = None user = user_crud.authenticate( - session=session, email=form_data.username, password=form_data.password, shop_id=None + session=session, email=form_data.username, password=form_data.password, shop_uuid=None ) if not user: raise HTTPException(status_code=400, detail="Incorrect email or password") @@ -39,6 +39,6 @@ def login_access_token( access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES) return Token( access_token=security.create_access_token( - user.id, expires_delta=access_token_expires + user.uuid, expires_delta=access_token_expires ) ) diff --git a/backend/app/api/routes/shop_routes.py b/backend/app/api/routes/shop_routes.py index 30014ab..49ea422 100644 --- a/backend/app/api/routes/shop_routes.py +++ b/backend/app/api/routes/shop_routes.py @@ -1,18 +1,18 @@ -from fastapi import APIRouter +from fastapi import APIRouter, HTTPException, status from app.api.dependencies import CurrentOwnerUser, SessionDep from app.schemas.shop_schemas import ShopCreate from app.schemas.user_schemas import Token +from app.crud.shop_crud import create_shop -router = APIRouter(prefix="/shop", tags=["Shop"]) +router = APIRouter(prefix="/shop", tags=["Dashboard"]) -@router.post("") +@router.post("", response_model=bool, status_code=201) def register_new_shop( session: SessionDep, current_user: CurrentOwnerUser, shop_data: ShopCreate ) -> Token: - """ - OAuth2 compatible token login, get an access token for future requests - """ + create_shop(session, shop_data, current_user) + return True diff --git a/backend/app/api/routes/user_routes.py b/backend/app/api/routes/user_routes.py index 200eea3..7847bcf 100644 --- a/backend/app/api/routes/user_routes.py +++ b/backend/app/api/routes/user_routes.py @@ -1,38 +1,35 @@ import logging import re -from fastapi import APIRouter, Body, HTTPException, status +from fastapi import APIRouter, HTTPException, status from sqlalchemy.exc import IntegrityError -from app.api.dependencies import SessionDep +from app.api.dependencies import CurrentOwnerUser, SessionDep from app.crud import user_crud from app.database.models.user_model import UserRole -from app.schemas.user_schemas import UserRegister +from app.schemas.user_schemas import UserRegister, UserUpdate logger = logging.getLogger(__name__) +INTERNAL_SERVER_ERROR = HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal server error") + router = APIRouter( prefix="/user", - tags=["User"] + tags=["User", "Dashboard"] ) -@router.delete("/delete", summary="Delete user") -async def delete_user(): - raise NotImplementedError("delete_user() needs to be implemented.") +@router.get("", summary="Get information about currently logged in user") +async def get_user(session: SessionDep, current_user: CurrentOwnerUser): + pass -@router.delete("/logout", summary="User logout") -async def logout(): - raise NotImplementedError("logout() needs to be implemented.") - - -@router.post("/register", summary="Register new user") +@router.post("", summary="Register new user", status_code=status.HTTP_201_CREATED, response_model=bool) async def register(session: SessionDep, user_data: UserRegister): try: user_crud.create_user(session, user_data, None, UserRole.OWNER) - return {"detail": "Registered succeesfully"} + return True except IntegrityError as e: field_mapping = {"uuid": "email"} # If a UUID is duplicate, it means email is in use @@ -49,10 +46,17 @@ async def register(session: SessionDep, user_data: UserRegister): detail=detail ) except Exception as e: + if isinstance(e, HTTPException): + raise logger.error(e) - raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Failed to register") + raise INTERNAL_SERVER_ERROR -@router.put("/update", summary="Update user details") -async def update_user(data: dict = Body(...)): - raise NotImplementedError("update_user() needs to be implemented.") +@router.delete("", summary="Delete user") +async def delete_user(): + raise HTTPException(status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="delete_user() not implemented") + + +@router.put("", summary="Update user details") +async def update_user(data: UserUpdate): + raise HTTPException(status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="update_user() not implemented") diff --git a/backend/app/database/models/shop_model.py b/backend/app/database/models/shop_model.py index 21639fa..5e7bb41 100644 --- a/backend/app/database/models/shop_model.py +++ b/backend/app/database/models/shop_model.py @@ -34,6 +34,14 @@ class ShopBusinessHours(BaseModel): hours: list[ShopBusinessHourEntry] +class ShopAddress(SQLModel): + street: str = Field(max_length=255, nullable=False) + city: str = Field(max_length=100, nullable=False) + state: str = Field(max_length=100, nullable=True) + postal_code: str = Field(max_length=20, nullable=False) + country: str = Field(max_length=100, nullable=False) + + class Shop(SQLModel, table=True): __tablename__ = 'shop' @@ -48,16 +56,11 @@ class Shop(SQLModel, table=True): logo: Optional[str] = Field(max_length=100) contact_email: str = Field(max_length=128, nullable=False, unique=True) phone_number: str = Field(max_length=15, nullable=False) - address: str = Field(nullable=True) + address: ShopAddress = Field(sa_column=Column(JSONB, nullable=False, default=lambda: {})) + business_hours: ShopBusinessHours = Field(sa_column=Column(JSONB, nullable=False, default=lambda: {})) + links: ShopLinks = Field(sa_column=Column(JSONB, nullable=False, default=lambda: {})) currency: str = Field(max_length=3, nullable=False) - business_hours: ShopBusinessHours = Field( - sa_column=Column(JSONB, nullable=False, default=lambda: {}) - ) - links: ShopLinks = Field( - sa_column=Column(JSONB, nullable=False, default=lambda: {}) - ) - owner: Optional["User"] = Relationship( back_populates='owned_shop', sa_relationship_kwargs={"foreign_keys": "[Shop.owner_id]"} @@ -68,10 +71,11 @@ class Shop(SQLModel, table=True): sa_relationship_kwargs={"foreign_keys": "[User.shop_id]"} ) - __table_args__ = ( - CheckConstraint("business_hours ? 'hours'", name="check_business_hours_keys"), - CheckConstraint("links ? 'links'", name="check_links_keys"), - ) + # __table_args__ = ( + # CheckConstraint("business_hours ? 'hours'", name="check_business_hours_keys"), + # CheckConstraint("links ? 'links'", name="check_links_keys"), + # CheckConstraint("address ? 'address'", name="check_address_keys") + # ) __all__ = ["Shop", "ShopBusinessHours", "ShopLinks", "ShopStatus"] diff --git a/backend/app/schemas/shop_schemas.py b/backend/app/schemas/shop_schemas.py index f7f788c..94d76d8 100644 --- a/backend/app/schemas/shop_schemas.py +++ b/backend/app/schemas/shop_schemas.py @@ -1,8 +1,14 @@ +from pydantic import EmailStr from sqlmodel import Field, SQLModel +from app.database.models.shop_model import ShopAddress + class ShopCreate(SQLModel): name: str = Field(max_length=100, nullable=False, unique=True) description: str = Field(max_length=500, nullable=False) currency: str = Field(max_length=3, nullable=False) + contact_email: EmailStr = Field() + contact_phone_number: str = Field(min_length=2, max_length=16, schema_extra={"pattern": r'^\+[1-9]\d{1,14}$'}) + address: ShopAddress diff --git a/backend/app/schemas/user_schemas.py b/backend/app/schemas/user_schemas.py index fb7dbf5..2c4dc6f 100644 --- a/backend/app/schemas/user_schemas.py +++ b/backend/app/schemas/user_schemas.py @@ -1,14 +1,15 @@ import re -from pydantic import EmailStr, model_validator -from sqlmodel import Field, SQLModel +from typing import Optional + +from pydantic import BaseModel, EmailStr, Field, model_validator -class UserRegister(SQLModel): +class UserRegister(BaseModel): username: str = Field(min_length=3, max_length=64) email: EmailStr = Field() - phone_number: str = Field(min_length=2, max_length=16, schema_extra={"pattern": r'^\+[1-9]\d{1,14}$'}) - password: str = Field(min_length=8, max_length=128, - description="Password must be at least 8 and at most 128 characters long, contain a lower case, upper case letter, a number and a special character (#?!@$ %^&*-)") + phone_number: str = Field(min_length=2, max_length=16, pattern=r'^\+[1-9]\d{1,14}$') + password: str = Field(min_length=8, max_length=128, examples=["Abc123#!"], + description="Password must conform to this regex: \n```\n^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$ %^&*-]).{8,128}$\n```") @model_validator(mode="after") def validate_using_regex(self): @@ -20,11 +21,29 @@ class UserRegister(SQLModel): if not re.match(password_regex, self.password): raise ValueError("Password is too weak") +class UserUpdate(BaseModel): + username: Optional[str] = Field(None, min_length=3, max_length=64) + first_name: Optional[str] = Field(None, max_length=64) + last_name: Optional[str] = Field(None, max_length=64) + email: Optional[EmailStr] = Field(None) + phone_number: Optional[str] = Field(None, min_length=2, max_length=16, pattern=r'^\+[1-9]\d{1,14}$') + password: Optional[str] = Field(None, min_length=8, max_length=128, examples=["Abc123#!"], + description="Password must conform to this regex: \n```\n^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$ %^&*-]).{8,128}$\n```") -class Token(SQLModel): + @model_validator(mode="after") + def validate_using_regex(self): + self.__validate_password() + return self + + def __validate_password(self): + password_regex = r"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$ %^&*-]).{8,128}$" + if not re.match(password_regex, self.password): + raise ValueError("Password is too weak") + +class Token(BaseModel): access_token: str token_type: str = "bearer" -class TokenPayload(SQLModel): +class TokenPayload(BaseModel): sub: str | None = None diff --git a/backend/app/utils/propagate.py b/backend/app/utils/propagate.py index bfddc24..1acb661 100644 --- a/backend/app/utils/propagate.py +++ b/backend/app/utils/propagate.py @@ -1,27 +1,19 @@ +import logging from functools import wraps -from fastapi import HTTPException +from fastapi import HTTPException, status -from sqlalchemy.exc import DatabaseError as SqlAlchemyDatabaseError - -from app.core.errors import RepositoryError, ServiceError +logger = logging.getLogger(__name__) -def propagate_db_error_to_service(func): +def raise_http_errors(func): @wraps(func) def wrapper(*args, **kwargs): try: return func(*args, **kwargs) - except (SqlAlchemyDatabaseError, RepositoryError) as e: - raise ServiceError(str(e)) from e - return wrapper - - -def propagate_service_errors_to_http_errors(func): - @wraps(func) - def wrapper(*args, **kwargs): - try: - return func(*args, **kwargs) - except ServiceError as e: - raise HTTPException(status_code=500, detail=str(e)) from e + except Exception as e: + if isinstance(e, HTTPException): + raise + logger.error(e) + raise HTTPException(status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, detail="Internal server error") return wrapper diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 6681c5a..6f4c281 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -32,6 +32,7 @@ ignore = [ "B008", # do not perform function calls in argument defaults "W191", # indentation contains tabs "B904", # Allow raising exceptions without from e, for HTTPException + "UP007", ] [tool.autopep8] diff --git a/frontend/src/client/client.gen.ts b/frontend/src/client/client.gen.ts deleted file mode 100644 index bbe7d19..0000000 --- a/frontend/src/client/client.gen.ts +++ /dev/null @@ -1,18 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -import type { ClientOptions } from './types.gen'; -import { type Config, type ClientOptions as DefaultClientOptions, createClient, createConfig } from '@hey-api/client-axios'; - -/** - * The `createClientConfig()` function will be called on client initialization - * and the returned object will become the client's initial configuration. - * - * You may want to initialize your client this way instead of calling - * `setConfig()`. This is useful for example if you're using Next.js - * to ensure your client always has the correct values. - */ -export type CreateClientConfig = (override?: Config) => Config & T>; - -export const client = createClient(createConfig({ - baseURL: 'http://localhost:8000' -})); \ No newline at end of file diff --git a/frontend/src/client/index.ts b/frontend/src/client/index.ts deleted file mode 100644 index e64537d..0000000 --- a/frontend/src/client/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts -export * from './types.gen'; -export * from './sdk.gen'; \ No newline at end of file diff --git a/frontend/src/client/sdk.gen.ts b/frontend/src/client/sdk.gen.ts deleted file mode 100644 index 261834f..0000000 --- a/frontend/src/client/sdk.gen.ts +++ /dev/null @@ -1,217 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -import { type Options as ClientOptions, type TDataShape, type Client, urlSearchParamsBodySerializer } from '@hey-api/client-axios'; -import type { CartShowCartData, CartAddToCartData, CartAddToCartError, CartRemoveFromCartData, CartRemoveFromCartError, CartUpdateCountInCartData, CartUpdateCountInCartError, CartPurchaseData, UserDeleteUserData, UserLogoutData, UserRegisterData, UserRegisterError, UserUpdateUserData, UserUpdateUserError, UtilsHealthCheckData, UtilsHealthCheckResponse, UtilsTestDbData, UtilsTestDbResponse, LoginLoginAccessTokenData, LoginLoginAccessTokenResponse, LoginLoginAccessTokenError, ShopLoginAccessTokenData, ShopLoginAccessTokenResponse, ShopLoginAccessTokenError, ShopDeleteUserData, ShopDeleteUserError, ShopLogoutData, ShopRegisterData, ShopRegisterError, ShopUpdateUserData, ShopUpdateUserError } from './types.gen'; -import { client as _heyApiClient } from './client.gen'; - -export type Options = ClientOptions & { - /** - * You can provide a client instance returned by `createClient()` instead of - * individual options. This might be also useful if you want to implement a - * custom client. - */ - client?: Client; - /** - * You can pass arbitrary values through the `meta` object. This can be - * used to access values that aren't defined as part of the SDK function. - */ - meta?: Record; -}; - -/** - * Show Cart - */ -export const cartShowCart = (options?: Options) => { - return (options?.client ?? _heyApiClient).get({ - url: '/cart/', - ...options - }); -}; - -/** - * Add To Cart - */ -export const cartAddToCart = (options: Options) => { - return (options.client ?? _heyApiClient).put({ - url: '/cart/add/{product_id}', - ...options - }); -}; - -/** - * Remove From Cart - */ -export const cartRemoveFromCart = (options: Options) => { - return (options.client ?? _heyApiClient).delete({ - url: '/cart/remove/{product_id}', - ...options - }); -}; - -/** - * Update Count In Cart - */ -export const cartUpdateCountInCart = (options: Options) => { - return (options.client ?? _heyApiClient).put({ - url: '/cart/update/{product_id}', - ...options - }); -}; - -/** - * Purchase - */ -export const cartPurchase = (options?: Options) => { - return (options?.client ?? _heyApiClient).get({ - url: '/cart/purchase', - ...options - }); -}; - -/** - * Delete user - */ -export const userDeleteUser = (options?: Options) => { - return (options?.client ?? _heyApiClient).delete({ - url: '/user/delete', - ...options - }); -}; - -/** - * User logout - */ -export const userLogout = (options?: Options) => { - return (options?.client ?? _heyApiClient).delete({ - url: '/user/logout', - ...options - }); -}; - -/** - * Register new user - */ -export const userRegister = (options: Options) => { - return (options.client ?? _heyApiClient).post({ - url: '/user/register', - ...options, - headers: { - 'Content-Type': 'application/json', - ...options?.headers - } - }); -}; - -/** - * Update user details - */ -export const userUpdateUser = (options: Options) => { - return (options.client ?? _heyApiClient).put({ - url: '/user/update', - ...options, - headers: { - 'Content-Type': 'application/json', - ...options?.headers - } - }); -}; - -/** - * Health Check - */ -export const utilsHealthCheck = (options?: Options) => { - return (options?.client ?? _heyApiClient).get({ - url: '/utils/health-check/', - ...options - }); -}; - -/** - * Test Db - */ -export const utilsTestDb = (options?: Options) => { - return (options?.client ?? _heyApiClient).get({ - url: '/utils/test-db/', - ...options - }); -}; - -/** - * Login Access Token - * OAuth2 compatible token login, get an access token for future requests - */ -export const loginLoginAccessToken = (options: Options) => { - return (options.client ?? _heyApiClient).post({ - ...urlSearchParamsBodySerializer, - url: '/login/access-token', - ...options, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - ...options?.headers - } - }); -}; - -/** - * Login Access Token - * OAuth2 compatible token login, get an access token for future requests - */ -export const shopLoginAccessToken = (options: Options) => { - return (options.client ?? _heyApiClient).post({ - ...urlSearchParamsBodySerializer, - url: '/shop/{shop_uuid}/login/access-token', - ...options, - headers: { - 'Content-Type': 'application/x-www-form-urlencoded', - ...options?.headers - } - }); -}; - -/** - * Delete user - */ -export const shopDeleteUser = (options: Options) => { - return (options.client ?? _heyApiClient).delete({ - url: '/shop/{shop_uuid}/user/delete', - ...options - }); -}; - -/** - * User logout - */ -export const shopLogout = (options?: Options) => { - return (options?.client ?? _heyApiClient).delete({ - url: '/shop/{shop_uuid}/user/logout', - ...options - }); -}; - -/** - * Register new user - */ -export const shopRegister = (options: Options) => { - return (options.client ?? _heyApiClient).post({ - url: '/shop/{shop_uuid}/user/register', - ...options, - headers: { - 'Content-Type': 'application/json', - ...options?.headers - } - }); -}; - -/** - * Update user details - */ -export const shopUpdateUser = (options: Options) => { - return (options.client ?? _heyApiClient).put({ - url: '/shop/{shop_uuid}/user/update', - ...options, - headers: { - 'Content-Type': 'application/json', - ...options?.headers - } - }); -}; \ No newline at end of file diff --git a/frontend/src/client/types.gen.ts b/frontend/src/client/types.gen.ts deleted file mode 100644 index 8846a6b..0000000 --- a/frontend/src/client/types.gen.ts +++ /dev/null @@ -1,408 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type BodyLoginLoginAccessToken = { - grant_type?: string | null; - username: string; - password: string; - scope?: string; - client_id?: string | null; - client_secret?: string | null; -}; - -export type BodyShopLoginAccessToken = { - grant_type?: string | null; - username: string; - password: string; - scope?: string; - client_id?: string | null; - client_secret?: string | null; -}; - -export type HttpValidationError = { - detail?: Array; -}; - -export type Token = { - access_token: string; - token_type?: string; -}; - -export type UserRegister = { - username: string; - email: string; - phone_number: string; - /** - * Password must be at least 8 and at most 128 characters long, contain a lower case, upper case letter, a number and a special character (#?!@$ %^&*-) - */ - password: string; -}; - -export type ValidationError = { - loc: Array; - msg: string; - type: string; -}; - -export type CartShowCartData = { - body?: never; - path?: never; - query?: never; - url: '/cart/'; -}; - -export type CartShowCartResponses = { - /** - * Successful Response - */ - 200: unknown; -}; - -export type CartAddToCartData = { - body?: never; - path: { - product_id: number; - }; - query?: { - /** - * Count must be greater than or equal to 1 - */ - count?: number; - }; - url: '/cart/add/{product_id}'; -}; - -export type CartAddToCartErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; -}; - -export type CartAddToCartError = CartAddToCartErrors[keyof CartAddToCartErrors]; - -export type CartAddToCartResponses = { - /** - * Successful Response - */ - 200: unknown; -}; - -export type CartRemoveFromCartData = { - body?: never; - path: { - product_id: number; - }; - query?: never; - url: '/cart/remove/{product_id}'; -}; - -export type CartRemoveFromCartErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; -}; - -export type CartRemoveFromCartError = CartRemoveFromCartErrors[keyof CartRemoveFromCartErrors]; - -export type CartRemoveFromCartResponses = { - /** - * Successful Response - */ - 200: unknown; -}; - -export type CartUpdateCountInCartData = { - body?: never; - path: { - product_id: number; - }; - query: { - /** - * Count must be provided - */ - count: number; - }; - url: '/cart/update/{product_id}'; -}; - -export type CartUpdateCountInCartErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; -}; - -export type CartUpdateCountInCartError = CartUpdateCountInCartErrors[keyof CartUpdateCountInCartErrors]; - -export type CartUpdateCountInCartResponses = { - /** - * Successful Response - */ - 200: unknown; -}; - -export type CartPurchaseData = { - body?: never; - path?: never; - query?: never; - url: '/cart/purchase'; -}; - -export type CartPurchaseResponses = { - /** - * Successful Response - */ - 200: unknown; -}; - -export type UserDeleteUserData = { - body?: never; - path?: never; - query?: never; - url: '/user/delete'; -}; - -export type UserDeleteUserResponses = { - /** - * Successful Response - */ - 200: unknown; -}; - -export type UserLogoutData = { - body?: never; - path?: never; - query?: never; - url: '/user/logout'; -}; - -export type UserLogoutResponses = { - /** - * Successful Response - */ - 200: unknown; -}; - -export type UserRegisterData = { - body: UserRegister; - path?: never; - query?: never; - url: '/user/register'; -}; - -export type UserRegisterErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; -}; - -export type UserRegisterError = UserRegisterErrors[keyof UserRegisterErrors]; - -export type UserRegisterResponses = { - /** - * Successful Response - */ - 200: unknown; -}; - -export type UserUpdateUserData = { - body: { - [key: string]: unknown; - }; - path?: never; - query?: never; - url: '/user/update'; -}; - -export type UserUpdateUserErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; -}; - -export type UserUpdateUserError = UserUpdateUserErrors[keyof UserUpdateUserErrors]; - -export type UserUpdateUserResponses = { - /** - * Successful Response - */ - 200: unknown; -}; - -export type UtilsHealthCheckData = { - body?: never; - path?: never; - query?: never; - url: '/utils/health-check/'; -}; - -export type UtilsHealthCheckResponses = { - /** - * Successful Response - */ - 200: boolean; -}; - -export type UtilsHealthCheckResponse = UtilsHealthCheckResponses[keyof UtilsHealthCheckResponses]; - -export type UtilsTestDbData = { - body?: never; - path?: never; - query?: never; - url: '/utils/test-db/'; -}; - -export type UtilsTestDbResponses = { - /** - * Successful Response - */ - 200: boolean; -}; - -export type UtilsTestDbResponse = UtilsTestDbResponses[keyof UtilsTestDbResponses]; - -export type LoginLoginAccessTokenData = { - body: BodyLoginLoginAccessToken; - path?: never; - query?: never; - url: '/login/access-token'; -}; - -export type LoginLoginAccessTokenErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; -}; - -export type LoginLoginAccessTokenError = LoginLoginAccessTokenErrors[keyof LoginLoginAccessTokenErrors]; - -export type LoginLoginAccessTokenResponses = { - /** - * Successful Response - */ - 200: Token; -}; - -export type LoginLoginAccessTokenResponse = LoginLoginAccessTokenResponses[keyof LoginLoginAccessTokenResponses]; - -export type ShopLoginAccessTokenData = { - body: BodyShopLoginAccessToken; - path?: never; - query?: never; - url: '/shop/{shop_uuid}/login/access-token'; -}; - -export type ShopLoginAccessTokenErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; -}; - -export type ShopLoginAccessTokenError = ShopLoginAccessTokenErrors[keyof ShopLoginAccessTokenErrors]; - -export type ShopLoginAccessTokenResponses = { - /** - * Successful Response - */ - 200: Token; -}; - -export type ShopLoginAccessTokenResponse = ShopLoginAccessTokenResponses[keyof ShopLoginAccessTokenResponses]; - -export type ShopDeleteUserData = { - body?: never; - path: { - shop_uuid: unknown; - }; - query?: never; - url: '/shop/{shop_uuid}/user/delete'; -}; - -export type ShopDeleteUserErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; -}; - -export type ShopDeleteUserError = ShopDeleteUserErrors[keyof ShopDeleteUserErrors]; - -export type ShopDeleteUserResponses = { - /** - * Successful Response - */ - 200: unknown; -}; - -export type ShopLogoutData = { - body?: never; - path?: never; - query?: never; - url: '/shop/{shop_uuid}/user/logout'; -}; - -export type ShopLogoutResponses = { - /** - * Successful Response - */ - 200: unknown; -}; - -export type ShopRegisterData = { - body: UserRegister; - path: { - shop_uuid: unknown; - }; - query?: never; - url: '/shop/{shop_uuid}/user/register'; -}; - -export type ShopRegisterErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; -}; - -export type ShopRegisterError = ShopRegisterErrors[keyof ShopRegisterErrors]; - -export type ShopRegisterResponses = { - /** - * Successful Response - */ - 200: unknown; -}; - -export type ShopUpdateUserData = { - body: { - [key: string]: unknown; - }; - path?: never; - query?: never; - url: '/shop/{shop_uuid}/user/update'; -}; - -export type ShopUpdateUserErrors = { - /** - * Validation Error - */ - 422: HttpValidationError; -}; - -export type ShopUpdateUserError = ShopUpdateUserErrors[keyof ShopUpdateUserErrors]; - -export type ShopUpdateUserResponses = { - /** - * Successful Response - */ - 200: unknown; -}; - -export type ClientOptions = { - baseURL: 'http://localhost:8000' | (string & {}); -}; \ No newline at end of file diff --git a/frontend/src/components/main-navbar.tsx b/frontend/src/components/main-navbar.tsx index f5b24f7..f0d4493 100644 --- a/frontend/src/components/main-navbar.tsx +++ b/frontend/src/components/main-navbar.tsx @@ -56,7 +56,7 @@ const MainNavbar = () => { diff --git a/frontend/src/hooks/useAuth.ts b/frontend/src/hooks/useAuth.ts index 713c4d5..1f7a132 100644 --- a/frontend/src/hooks/useAuth.ts +++ b/frontend/src/hooks/useAuth.ts @@ -2,15 +2,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query" import { useNavigate } from "@tanstack/react-router" import { useState } from "react" -import { - type BodyLoginLoginAccessToken as AccessToken, - type ApiError, - LoginService, - type UserPublic, - type UserRegister, - UsersService, -} from "@/client" -import { handleError } from "@/utils" +import { handleServerError } from "@/utils/handle-server-error" const isLoggedIn = () => { return localStorage.getItem("access_token") !== null @@ -31,10 +23,10 @@ const useAuth = () => { UsersService.registerUser({ requestBody: data }), onSuccess: () => { - navigate({ to: "/login" }) + navigate({ to: "/sign-in" }) }, onError: (err: ApiError) => { - handleError(err) + handleServerError(err) }, onSettled: () => { queryClient.invalidateQueries({ queryKey: ["users"] }) @@ -60,7 +52,7 @@ const useAuth = () => { const logout = () => { localStorage.removeItem("access_token") - navigate({ to: "/login" }) + navigate({ to: "/sign-in" }) } return {