Major addition. User register, login and update is now functional on frontend, removed UUID5 for UUID4 for users and many more changes
This commit is contained in:
parent
d87c280109
commit
d0690f2f06
2
.gitignore
vendored
2
.gitignore
vendored
@ -293,3 +293,5 @@ cython_debug/
|
||||
#.idea/
|
||||
|
||||
!frontend/src/lib
|
||||
|
||||
frontend/openapi.json
|
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -8,6 +8,7 @@
|
||||
// #endregion
|
||||
|
||||
// #region Frontend settings
|
||||
"prettier.configPath": "./frontend/.prettierrc" // Prettier config override
|
||||
"prettier.configPath": "./frontend/.prettierrc", // Prettier config override
|
||||
"biome.lspBin": "${workspaceFolder}/frontend"
|
||||
// #endregion
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ from app.api.routes import cart_routes, login_routes, shop, user_routes, utils_r
|
||||
|
||||
api_router = APIRouter()
|
||||
|
||||
api_router.include_router(cart_routes.router)
|
||||
api_router.include_router(user_routes.router)
|
||||
api_router.include_router(utils_routes.router)
|
||||
api_router.include_router(login_routes.router)
|
||||
|
@ -1,18 +1,18 @@
|
||||
from fastapi import APIRouter, HTTPException, status
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.api.dependencies import CurrentOwnerUser, SessionDep
|
||||
from app.crud.shop_crud import create_shop
|
||||
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=["Dashboard"])
|
||||
|
||||
|
||||
@router.post("", response_model=bool, status_code=201)
|
||||
@router.post("", status_code=201)
|
||||
def register_new_shop(
|
||||
session: SessionDep,
|
||||
current_user: CurrentOwnerUser,
|
||||
shop_data: ShopCreate
|
||||
) -> Token:
|
||||
) -> bool:
|
||||
create_shop(session, shop_data, current_user)
|
||||
return True
|
||||
|
@ -7,7 +7,7 @@ from sqlalchemy.exc import IntegrityError
|
||||
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, UserUpdate
|
||||
from app.schemas.user_schemas import UserPublic, UserRegister, UserUpdate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -21,8 +21,8 @@ router = APIRouter(
|
||||
|
||||
|
||||
@router.get("", summary="Get information about currently logged in user")
|
||||
async def get_user(session: SessionDep, current_user: CurrentOwnerUser):
|
||||
pass
|
||||
async def get_user(current_user: CurrentOwnerUser) -> UserPublic:
|
||||
return current_user
|
||||
|
||||
|
||||
@router.post("", summary="Register new user", status_code=status.HTTP_201_CREATED, response_model=bool)
|
||||
@ -40,11 +40,8 @@ async def register(session: SessionDep, user_data: UserRegister):
|
||||
column_name = "email"
|
||||
|
||||
detail = f"{field_mapping.get(column_name, column_name or 'Entry').capitalize()} already in use"
|
||||
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_409_CONFLICT,
|
||||
detail=detail
|
||||
)
|
||||
logger.warning("%s already exists in the database", column_name.capitalize)
|
||||
raise HTTPException(status_code=status.HTTP_409_CONFLICT, detail=detail)
|
||||
except Exception as e:
|
||||
if isinstance(e, HTTPException):
|
||||
raise
|
||||
@ -53,10 +50,11 @@ async def register(session: SessionDep, user_data: UserRegister):
|
||||
|
||||
|
||||
@router.delete("", summary="Delete user")
|
||||
async def delete_user():
|
||||
async def delete_user() -> bool:
|
||||
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")
|
||||
async def update_user(session: SessionDep, data: UserUpdate, current_user: CurrentOwnerUser) -> bool:
|
||||
user_crud.update_user(session, data, current_user)
|
||||
return True
|
||||
|
@ -1,5 +1,6 @@
|
||||
import logging
|
||||
from typing import Optional
|
||||
from uuid import UUID, uuid4
|
||||
from uuid import uuid4
|
||||
|
||||
from sqlmodel import Session, select
|
||||
|
||||
@ -7,12 +8,19 @@ from app.database.models.shop_model import Shop, ShopStatus
|
||||
from app.database.models.user_model import User
|
||||
from app.schemas.shop_schemas import ShopCreate
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
def get_shop_id_from_uuid(session: Session, shop_id: int) -> Optional[UUID]:
|
||||
def get_shop_by_id(session: Session, shop_id: int) -> Optional[Shop]:
|
||||
logger.debug("Getting shop by shop_id - %d", id)
|
||||
stmt = select(Shop).where(Shop.id == shop_id)
|
||||
db_shop = session.exec(stmt).one_or_none()
|
||||
return db_shop
|
||||
|
||||
def get_shop_by_uuid(session: Session, shop_uuid: str) -> Optional[Shop]:
|
||||
logger.debug("Getting shop by UUID - %s" , shop_uuid)
|
||||
stmt = select(Shop).where(Shop.uuid == shop_uuid)
|
||||
db_shop = session.exec(stmt).one_or_none()
|
||||
return db_shop
|
||||
|
||||
def create_shop(session: Session, shop_data: ShopCreate, creator: User) -> None:
|
||||
shop_uuid = uuid4()
|
||||
|
@ -1,37 +1,32 @@
|
||||
import logging
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
from uuid import UUID, uuid4
|
||||
|
||||
from sqlmodel import Session, select
|
||||
from fastapi import HTTPException, status
|
||||
from sqlmodel import Session, select, and_
|
||||
|
||||
from app.core.security import get_password_hash, verify_password
|
||||
from app.crud.shop_crud import get_shop_id_from_uuid
|
||||
from app.crud.shop_crud import get_shop_by_uuid
|
||||
from app.database.models.user_model import User, UserRole
|
||||
from app.schemas.user_schemas import UserRegister
|
||||
from app.schemas.user_schemas import UserRegister, UserUpdate
|
||||
from app.utils.models import generate_user_uuid5
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_user_by_generated_uuid(session: Session, email: str, shop_uuid: Optional[UUID]) -> Optional[User]:
|
||||
logger.debug("Getting shop id by UUID - %s", shop_uuid)
|
||||
shop_id = get_shop_id_from_uuid(session, shop_uuid)
|
||||
logger.debug("Generating user UUID5")
|
||||
user_uuid = generate_user_uuid5(email, shop_id)
|
||||
stmt = select(User).where(User.uuid == user_uuid)
|
||||
logger.debug("Executing select query")
|
||||
db_user = session.exec(stmt).one_or_none()
|
||||
return db_user
|
||||
|
||||
def create_user(session: Session, user_register: UserRegister, shop_uuid: Optional[UUID], user_role: UserRole):
|
||||
logger.debug("Getting shop id by UUID - %s", shop_uuid)
|
||||
shop_id = get_shop_id_from_uuid(session, shop_uuid)
|
||||
logger.debug("Generating user UUID5")
|
||||
user_uuid = generate_user_uuid5(user_register.email, shop_id)
|
||||
if shop_uuid:
|
||||
logger.debug("Fetching shop by UUID")
|
||||
shop_id = get_shop_by_uuid(session, shop_uuid).id
|
||||
else:
|
||||
logger.debug("No shop UUID provided -> Owner account is being created")
|
||||
shop_id = None
|
||||
|
||||
logger.debug("Hashing password")
|
||||
hashed_password = get_password_hash(user_register.password)
|
||||
|
||||
new_user = User(
|
||||
uuid=user_uuid,
|
||||
uuid=uuid4(),
|
||||
shop_id=shop_id,
|
||||
email=user_register.email,
|
||||
username=user_register.username,
|
||||
@ -39,20 +34,50 @@ def create_user(session: Session, user_register: UserRegister, shop_uuid: Option
|
||||
user_role=user_role,
|
||||
password=hashed_password
|
||||
)
|
||||
|
||||
logger.debug("Inserting new user")
|
||||
session.add(new_user)
|
||||
session.commit()
|
||||
|
||||
|
||||
def update_user(session: Session, user_update: UserUpdate, current_user: User):
|
||||
|
||||
current_user.email = user_update.email
|
||||
current_user.username = user_update.username
|
||||
current_user.phone_number = user_update.phone_number
|
||||
current_user.first_name = user_update.first_name
|
||||
current_user.last_name = user_update.last_name
|
||||
|
||||
session.commit()
|
||||
|
||||
|
||||
def get_user_by_uuid(session: Session, email: str, shop_uuid: Optional[UUID]) -> Optional[User]:
|
||||
if shop_uuid:
|
||||
shop_id = get_shop_by_uuid(session, shop_uuid).id
|
||||
else:
|
||||
shop_id = None
|
||||
|
||||
stmt = select(User).where(and_(
|
||||
User.email == email,
|
||||
User.shop_id == shop_id
|
||||
))
|
||||
logger.debug("Executing select query")
|
||||
db_user = session.exec(stmt).one_or_none()
|
||||
return db_user
|
||||
|
||||
|
||||
def authenticate(session: Session, email: str, password: str, shop_uuid: Optional[int]) -> Optional[User]:
|
||||
logger.debug("Getting shop id by UUID - %s", shop_uuid)
|
||||
shop_id = get_shop_id_from_uuid(session, shop_uuid)
|
||||
if shop_uuid:
|
||||
shop_id = get_shop_by_uuid(session, shop_uuid).id
|
||||
else:
|
||||
shop_id = None
|
||||
|
||||
logger.debug("Fetching user from db by email - %s", email)
|
||||
db_user = get_user_by_generated_uuid(session, email, shop_id)
|
||||
db_user = get_user_by_uuid(session, email, shop_id)
|
||||
if db_user is None:
|
||||
logger.warn("Didn't find User with email=%s for shop=%s", email, shop_uuid)
|
||||
logger.warning("Didn't find User with email=%s for shop=%s", email, shop_uuid)
|
||||
return None
|
||||
if not verify_password(plain_password=password, hashed_password=db_user.password):
|
||||
logger.warn("Found user with email=%s for shop=%s", email, shop_uuid)
|
||||
logger.warning("Found user with email=%s for shop=%s", email, shop_uuid)
|
||||
return None
|
||||
return db_user
|
||||
|
@ -4,7 +4,7 @@ from typing import Optional
|
||||
from uuid import UUID
|
||||
|
||||
from sqlalchemy import Column
|
||||
from sqlmodel import Enum, Field, Relationship, SQLModel
|
||||
from sqlmodel import Enum, Field, Relationship, SQLModel, UniqueConstraint
|
||||
|
||||
|
||||
class UserRole(PyEnum):
|
||||
@ -17,6 +17,9 @@ class UserRole(PyEnum):
|
||||
|
||||
class User(SQLModel, table=True):
|
||||
__tablename__ = "user"
|
||||
__table_args__ = (
|
||||
UniqueConstraint("email", "shop_id", name="uix_email_shop_id"),
|
||||
)
|
||||
|
||||
id: int = Field(primary_key=True)
|
||||
uuid: UUID = Field(nullable=False, unique=True)
|
||||
|
@ -1,5 +1,5 @@
|
||||
import re
|
||||
from typing import Optional
|
||||
import uuid
|
||||
|
||||
from pydantic import BaseModel, EmailStr, Field, model_validator
|
||||
|
||||
@ -7,9 +7,13 @@ from pydantic import BaseModel, EmailStr, Field, model_validator
|
||||
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, 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```")
|
||||
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):
|
||||
@ -17,28 +21,28 @@ class UserRegister(BaseModel):
|
||||
return self
|
||||
|
||||
def __validate_password(self):
|
||||
password_regex = r"^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$ %^&*-]).{8,128}$"
|
||||
password_regex = r"^(?=[^A-Z]*[A-Z])(?=[^a-z]*[a-z])(?=\D*\d)(?=[^#?!@$ %^&*-]*[#?!@$ %^&*-]).{8,128}$"
|
||||
|
||||
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```")
|
||||
email: EmailStr | None = Field()
|
||||
phone_number: str | None = Field(min_length=2, max_length=16, pattern=r"^\+[1-9]\d{1,14}$")
|
||||
username: str | None = Field(min_length=3, max_length=64)
|
||||
first_name: str | None = Field(None, max_length=64)
|
||||
last_name: str | None = Field(None, max_length=64)
|
||||
|
||||
@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 UserPublic(BaseModel):
|
||||
uuid: uuid.UUID
|
||||
username: str
|
||||
email: str
|
||||
first_name: str | None
|
||||
last_name: str | None
|
||||
phone_number: str
|
||||
|
||||
|
||||
class Token(BaseModel):
|
||||
access_token: str
|
||||
|
@ -1,6 +1,12 @@
|
||||
import logging
|
||||
from typing import Optional
|
||||
from uuid import uuid5, UUID, NAMESPACE_DNS
|
||||
from uuid import NAMESPACE_DNS, UUID, uuid5
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def generate_user_uuid5(email: str, shop_id: Optional[int]) -> UUID:
|
||||
unique_string = f"{email}-{shop_id}" if shop_id else email
|
||||
return uuid5(NAMESPACE_DNS, unique_string)
|
||||
generated_uuid = uuid5(NAMESPACE_DNS, unique_string)
|
||||
logger.debug("Generated user UUID5 - %s", generated_uuid)
|
||||
return generated_uuid
|
||||
|
@ -30,7 +30,6 @@ select = [
|
||||
ignore = [
|
||||
"E501", # line too long, handled by black
|
||||
"B008", # do not perform function calls in argument defaults
|
||||
"W191", # indentation contains tabs
|
||||
"B904", # Allow raising exceptions without from e, for HTTPException
|
||||
"UP007",
|
||||
]
|
||||
|
0
frontend/.env.example
Normal file
0
frontend/.env.example
Normal file
30
frontend/biome.json
Normal file
30
frontend/biome.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "https://biomejs.dev/schemas/1.9.4/schema.json",
|
||||
"vcs": {
|
||||
"enabled": false,
|
||||
"clientKind": "git",
|
||||
"useIgnoreFile": false
|
||||
},
|
||||
"files": {
|
||||
"ignoreUnknown": false,
|
||||
"ignore": []
|
||||
},
|
||||
"formatter": {
|
||||
"enabled": true,
|
||||
"indentStyle": "tab"
|
||||
},
|
||||
"organizeImports": {
|
||||
"enabled": true
|
||||
},
|
||||
"linter": {
|
||||
"enabled": true,
|
||||
"rules": {
|
||||
"recommended": true
|
||||
}
|
||||
},
|
||||
"javascript": {
|
||||
"formatter": {
|
||||
"quoteStyle": "double"
|
||||
}
|
||||
}
|
||||
}
|
16
frontend/openapi-ts.config.ts
Normal file
16
frontend/openapi-ts.config.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { defineConfig } from "@hey-api/openapi-ts";
|
||||
|
||||
export default defineConfig({
|
||||
input: "./openapi.json",
|
||||
output: {
|
||||
path: "./src/client"
|
||||
},
|
||||
plugins: [
|
||||
"legacy/axios",
|
||||
{
|
||||
name: "@hey-api/sdk",
|
||||
asClass: true,
|
||||
operationId: true
|
||||
}
|
||||
]
|
||||
});
|
1036
frontend/package-lock.json
generated
1036
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -11,7 +11,7 @@
|
||||
"format:check": "prettier --check .",
|
||||
"format": "prettier --write .",
|
||||
"knip": "knip",
|
||||
"generate-client": "openapi-ts --input http://localhost:8000/openapi.json --output ./src/client --client @hey-api/client-axios"
|
||||
"generate-client": "openapi-ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@hookform/resolvers": "^3.9.1",
|
||||
@ -51,6 +51,7 @@
|
||||
"react-day-picker": "^9.6.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-hook-form": "^7.54.0",
|
||||
"react-phone-number-input": "^3.4.12",
|
||||
"recharts": "^2.14.1",
|
||||
"tailwind-merge": "^3.0.1",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
|
21
frontend/src/client/core/ApiError.ts
Normal file
21
frontend/src/client/core/ApiError.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import type { ApiRequestOptions } from './ApiRequestOptions';
|
||||
import type { ApiResult } from './ApiResult';
|
||||
|
||||
export class ApiError extends Error {
|
||||
public readonly url: string;
|
||||
public readonly status: number;
|
||||
public readonly statusText: string;
|
||||
public readonly body: unknown;
|
||||
public readonly request: ApiRequestOptions;
|
||||
|
||||
constructor(request: ApiRequestOptions, response: ApiResult, message: string) {
|
||||
super(message);
|
||||
|
||||
this.name = 'ApiError';
|
||||
this.url = response.url;
|
||||
this.status = response.status;
|
||||
this.statusText = response.statusText;
|
||||
this.body = response.body;
|
||||
this.request = request;
|
||||
}
|
||||
}
|
21
frontend/src/client/core/ApiRequestOptions.ts
Normal file
21
frontend/src/client/core/ApiRequestOptions.ts
Normal file
@ -0,0 +1,21 @@
|
||||
export type ApiRequestOptions<T = unknown> = {
|
||||
readonly body?: any;
|
||||
readonly cookies?: Record<string, unknown>;
|
||||
readonly errors?: Record<number | string, string>;
|
||||
readonly formData?: Record<string, unknown> | any[] | Blob | File;
|
||||
readonly headers?: Record<string, unknown>;
|
||||
readonly mediaType?: string;
|
||||
readonly method:
|
||||
| 'DELETE'
|
||||
| 'GET'
|
||||
| 'HEAD'
|
||||
| 'OPTIONS'
|
||||
| 'PATCH'
|
||||
| 'POST'
|
||||
| 'PUT';
|
||||
readonly path?: Record<string, unknown>;
|
||||
readonly query?: Record<string, unknown>;
|
||||
readonly responseHeader?: string;
|
||||
readonly responseTransformer?: (data: unknown) => Promise<T>;
|
||||
readonly url: string;
|
||||
};
|
7
frontend/src/client/core/ApiResult.ts
Normal file
7
frontend/src/client/core/ApiResult.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export type ApiResult<TData = any> = {
|
||||
readonly body: TData;
|
||||
readonly ok: boolean;
|
||||
readonly status: number;
|
||||
readonly statusText: string;
|
||||
readonly url: string;
|
||||
};
|
126
frontend/src/client/core/CancelablePromise.ts
Normal file
126
frontend/src/client/core/CancelablePromise.ts
Normal file
@ -0,0 +1,126 @@
|
||||
export class CancelError extends Error {
|
||||
constructor(message: string) {
|
||||
super(message);
|
||||
this.name = 'CancelError';
|
||||
}
|
||||
|
||||
public get isCancelled(): boolean {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
export interface OnCancel {
|
||||
readonly isResolved: boolean;
|
||||
readonly isRejected: boolean;
|
||||
readonly isCancelled: boolean;
|
||||
|
||||
(cancelHandler: () => void): void;
|
||||
}
|
||||
|
||||
export class CancelablePromise<T> implements Promise<T> {
|
||||
private _isResolved: boolean;
|
||||
private _isRejected: boolean;
|
||||
private _isCancelled: boolean;
|
||||
readonly cancelHandlers: (() => void)[];
|
||||
readonly promise: Promise<T>;
|
||||
private _resolve?: (value: T | PromiseLike<T>) => void;
|
||||
private _reject?: (reason?: unknown) => void;
|
||||
|
||||
constructor(
|
||||
executor: (
|
||||
resolve: (value: T | PromiseLike<T>) => void,
|
||||
reject: (reason?: unknown) => void,
|
||||
onCancel: OnCancel
|
||||
) => void
|
||||
) {
|
||||
this._isResolved = false;
|
||||
this._isRejected = false;
|
||||
this._isCancelled = false;
|
||||
this.cancelHandlers = [];
|
||||
this.promise = new Promise<T>((resolve, reject) => {
|
||||
this._resolve = resolve;
|
||||
this._reject = reject;
|
||||
|
||||
const onResolve = (value: T | PromiseLike<T>): void => {
|
||||
if (this._isResolved || this._isRejected || this._isCancelled) {
|
||||
return;
|
||||
}
|
||||
this._isResolved = true;
|
||||
if (this._resolve) this._resolve(value);
|
||||
};
|
||||
|
||||
const onReject = (reason?: unknown): void => {
|
||||
if (this._isResolved || this._isRejected || this._isCancelled) {
|
||||
return;
|
||||
}
|
||||
this._isRejected = true;
|
||||
if (this._reject) this._reject(reason);
|
||||
};
|
||||
|
||||
const onCancel = (cancelHandler: () => void): void => {
|
||||
if (this._isResolved || this._isRejected || this._isCancelled) {
|
||||
return;
|
||||
}
|
||||
this.cancelHandlers.push(cancelHandler);
|
||||
};
|
||||
|
||||
Object.defineProperty(onCancel, 'isResolved', {
|
||||
get: (): boolean => this._isResolved,
|
||||
});
|
||||
|
||||
Object.defineProperty(onCancel, 'isRejected', {
|
||||
get: (): boolean => this._isRejected,
|
||||
});
|
||||
|
||||
Object.defineProperty(onCancel, 'isCancelled', {
|
||||
get: (): boolean => this._isCancelled,
|
||||
});
|
||||
|
||||
return executor(onResolve, onReject, onCancel as OnCancel);
|
||||
});
|
||||
}
|
||||
|
||||
get [Symbol.toStringTag]() {
|
||||
return "Cancellable Promise";
|
||||
}
|
||||
|
||||
public then<TResult1 = T, TResult2 = never>(
|
||||
onFulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | null,
|
||||
onRejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null
|
||||
): Promise<TResult1 | TResult2> {
|
||||
return this.promise.then(onFulfilled, onRejected);
|
||||
}
|
||||
|
||||
public catch<TResult = never>(
|
||||
onRejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null
|
||||
): Promise<T | TResult> {
|
||||
return this.promise.catch(onRejected);
|
||||
}
|
||||
|
||||
public finally(onFinally?: (() => void) | null): Promise<T> {
|
||||
return this.promise.finally(onFinally);
|
||||
}
|
||||
|
||||
public cancel(): void {
|
||||
if (this._isResolved || this._isRejected || this._isCancelled) {
|
||||
return;
|
||||
}
|
||||
this._isCancelled = true;
|
||||
if (this.cancelHandlers.length) {
|
||||
try {
|
||||
for (const cancelHandler of this.cancelHandlers) {
|
||||
cancelHandler();
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn('Cancellation threw an error', error);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.cancelHandlers.length = 0;
|
||||
if (this._reject) this._reject(new CancelError('Request aborted'));
|
||||
}
|
||||
|
||||
public get isCancelled(): boolean {
|
||||
return this._isCancelled;
|
||||
}
|
||||
}
|
57
frontend/src/client/core/OpenAPI.ts
Normal file
57
frontend/src/client/core/OpenAPI.ts
Normal file
@ -0,0 +1,57 @@
|
||||
import type { AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
import type { ApiRequestOptions } from './ApiRequestOptions';
|
||||
|
||||
type Headers = Record<string, string>;
|
||||
type Middleware<T> = (value: T) => T | Promise<T>;
|
||||
type Resolver<T> = (options: ApiRequestOptions<T>) => Promise<T>;
|
||||
|
||||
export class Interceptors<T> {
|
||||
_fns: Middleware<T>[];
|
||||
|
||||
constructor() {
|
||||
this._fns = [];
|
||||
}
|
||||
|
||||
eject(fn: Middleware<T>): void {
|
||||
const index = this._fns.indexOf(fn);
|
||||
if (index !== -1) {
|
||||
this._fns = [...this._fns.slice(0, index), ...this._fns.slice(index + 1)];
|
||||
}
|
||||
}
|
||||
|
||||
use(fn: Middleware<T>): void {
|
||||
this._fns = [...this._fns, fn];
|
||||
}
|
||||
}
|
||||
|
||||
export type OpenAPIConfig = {
|
||||
BASE: string;
|
||||
CREDENTIALS: 'include' | 'omit' | 'same-origin';
|
||||
ENCODE_PATH?: ((path: string) => string) | undefined;
|
||||
HEADERS?: Headers | Resolver<Headers> | undefined;
|
||||
PASSWORD?: string | Resolver<string> | undefined;
|
||||
TOKEN?: string | Resolver<string> | undefined;
|
||||
USERNAME?: string | Resolver<string> | undefined;
|
||||
VERSION: string;
|
||||
WITH_CREDENTIALS: boolean;
|
||||
interceptors: {
|
||||
request: Interceptors<AxiosRequestConfig>;
|
||||
response: Interceptors<AxiosResponse>;
|
||||
};
|
||||
};
|
||||
|
||||
export const OpenAPI: OpenAPIConfig = {
|
||||
BASE: '',
|
||||
CREDENTIALS: 'include',
|
||||
ENCODE_PATH: undefined,
|
||||
HEADERS: undefined,
|
||||
PASSWORD: undefined,
|
||||
TOKEN: undefined,
|
||||
USERNAME: undefined,
|
||||
VERSION: '0.0.1',
|
||||
WITH_CREDENTIALS: false,
|
||||
interceptors: {
|
||||
request: new Interceptors(),
|
||||
response: new Interceptors(),
|
||||
},
|
||||
};
|
347
frontend/src/client/core/request.ts
Normal file
347
frontend/src/client/core/request.ts
Normal file
@ -0,0 +1,347 @@
|
||||
import axios from 'axios';
|
||||
import type { AxiosError, AxiosRequestConfig, AxiosResponse, AxiosInstance } from 'axios';
|
||||
|
||||
import { ApiError } from './ApiError';
|
||||
import type { ApiRequestOptions } from './ApiRequestOptions';
|
||||
import type { ApiResult } from './ApiResult';
|
||||
import { CancelablePromise } from './CancelablePromise';
|
||||
import type { OnCancel } from './CancelablePromise';
|
||||
import type { OpenAPIConfig } from './OpenAPI';
|
||||
|
||||
export const isString = (value: unknown): value is string => {
|
||||
return typeof value === 'string';
|
||||
};
|
||||
|
||||
export const isStringWithValue = (value: unknown): value is string => {
|
||||
return isString(value) && value !== '';
|
||||
};
|
||||
|
||||
export const isBlob = (value: any): value is Blob => {
|
||||
return value instanceof Blob;
|
||||
};
|
||||
|
||||
export const isFormData = (value: unknown): value is FormData => {
|
||||
return value instanceof FormData;
|
||||
};
|
||||
|
||||
export const isSuccess = (status: number): boolean => {
|
||||
return status >= 200 && status < 300;
|
||||
};
|
||||
|
||||
export const base64 = (str: string): string => {
|
||||
try {
|
||||
return btoa(str);
|
||||
} catch (err) {
|
||||
// @ts-ignore
|
||||
return Buffer.from(str).toString('base64');
|
||||
}
|
||||
};
|
||||
|
||||
export const getQueryString = (params: Record<string, unknown>): string => {
|
||||
const qs: string[] = [];
|
||||
|
||||
const append = (key: string, value: unknown) => {
|
||||
qs.push(`${encodeURIComponent(key)}=${encodeURIComponent(String(value))}`);
|
||||
};
|
||||
|
||||
const encodePair = (key: string, value: unknown) => {
|
||||
if (value === undefined || value === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (value instanceof Date) {
|
||||
append(key, value.toISOString());
|
||||
} else if (Array.isArray(value)) {
|
||||
value.forEach(v => encodePair(key, v));
|
||||
} else if (typeof value === 'object') {
|
||||
Object.entries(value).forEach(([k, v]) => encodePair(`${key}[${k}]`, v));
|
||||
} else {
|
||||
append(key, value);
|
||||
}
|
||||
};
|
||||
|
||||
Object.entries(params).forEach(([key, value]) => encodePair(key, value));
|
||||
|
||||
return qs.length ? `?${qs.join('&')}` : '';
|
||||
};
|
||||
|
||||
const getUrl = (config: OpenAPIConfig, options: ApiRequestOptions): string => {
|
||||
const encoder = config.ENCODE_PATH || encodeURI;
|
||||
|
||||
const path = options.url
|
||||
.replace('{api-version}', config.VERSION)
|
||||
.replace(/{(.*?)}/g, (substring: string, group: string) => {
|
||||
if (options.path?.hasOwnProperty(group)) {
|
||||
return encoder(String(options.path[group]));
|
||||
}
|
||||
return substring;
|
||||
});
|
||||
|
||||
const url = config.BASE + path;
|
||||
return options.query ? url + getQueryString(options.query) : url;
|
||||
};
|
||||
|
||||
export const getFormData = (options: ApiRequestOptions): FormData | undefined => {
|
||||
if (options.formData) {
|
||||
const formData = new FormData();
|
||||
|
||||
const process = (key: string, value: unknown) => {
|
||||
if (isString(value) || isBlob(value)) {
|
||||
formData.append(key, value);
|
||||
} else {
|
||||
formData.append(key, JSON.stringify(value));
|
||||
}
|
||||
};
|
||||
|
||||
Object.entries(options.formData)
|
||||
.filter(([, value]) => value !== undefined && value !== null)
|
||||
.forEach(([key, value]) => {
|
||||
if (Array.isArray(value)) {
|
||||
value.forEach(v => process(key, v));
|
||||
} else {
|
||||
process(key, value);
|
||||
}
|
||||
});
|
||||
|
||||
return formData;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
type Resolver<T> = (options: ApiRequestOptions<T>) => Promise<T>;
|
||||
|
||||
export const resolve = async <T>(options: ApiRequestOptions<T>, resolver?: T | Resolver<T>): Promise<T | undefined> => {
|
||||
if (typeof resolver === 'function') {
|
||||
return (resolver as Resolver<T>)(options);
|
||||
}
|
||||
return resolver;
|
||||
};
|
||||
|
||||
export const getHeaders = async <T>(config: OpenAPIConfig, options: ApiRequestOptions<T>): Promise<Record<string, string>> => {
|
||||
const [token, username, password, additionalHeaders] = await Promise.all([
|
||||
// @ts-ignore
|
||||
resolve(options, config.TOKEN),
|
||||
// @ts-ignore
|
||||
resolve(options, config.USERNAME),
|
||||
// @ts-ignore
|
||||
resolve(options, config.PASSWORD),
|
||||
// @ts-ignore
|
||||
resolve(options, config.HEADERS),
|
||||
]);
|
||||
|
||||
const headers = Object.entries({
|
||||
Accept: 'application/json',
|
||||
...additionalHeaders,
|
||||
...options.headers,
|
||||
})
|
||||
.filter(([, value]) => value !== undefined && value !== null)
|
||||
.reduce((headers, [key, value]) => ({
|
||||
...headers,
|
||||
[key]: String(value),
|
||||
}), {} as Record<string, string>);
|
||||
|
||||
if (isStringWithValue(token)) {
|
||||
headers['Authorization'] = `Bearer ${token}`;
|
||||
}
|
||||
|
||||
if (isStringWithValue(username) && isStringWithValue(password)) {
|
||||
const credentials = base64(`${username}:${password}`);
|
||||
headers['Authorization'] = `Basic ${credentials}`;
|
||||
}
|
||||
|
||||
if (options.body !== undefined) {
|
||||
if (options.mediaType) {
|
||||
headers['Content-Type'] = options.mediaType;
|
||||
} else if (isBlob(options.body)) {
|
||||
headers['Content-Type'] = options.body.type || 'application/octet-stream';
|
||||
} else if (isString(options.body)) {
|
||||
headers['Content-Type'] = 'text/plain';
|
||||
} else if (!isFormData(options.body)) {
|
||||
headers['Content-Type'] = 'application/json';
|
||||
}
|
||||
} else if (options.formData !== undefined) {
|
||||
if (options.mediaType) {
|
||||
headers['Content-Type'] = options.mediaType;
|
||||
}
|
||||
}
|
||||
|
||||
return headers;
|
||||
};
|
||||
|
||||
export const getRequestBody = (options: ApiRequestOptions): unknown => {
|
||||
if (options.body) {
|
||||
return options.body;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const sendRequest = async <T>(
|
||||
config: OpenAPIConfig,
|
||||
options: ApiRequestOptions<T>,
|
||||
url: string,
|
||||
body: unknown,
|
||||
formData: FormData | undefined,
|
||||
headers: Record<string, string>,
|
||||
onCancel: OnCancel,
|
||||
axiosClient: AxiosInstance
|
||||
): Promise<AxiosResponse<T>> => {
|
||||
const controller = new AbortController();
|
||||
|
||||
let requestConfig: AxiosRequestConfig = {
|
||||
data: body ?? formData,
|
||||
headers,
|
||||
method: options.method,
|
||||
signal: controller.signal,
|
||||
url,
|
||||
withCredentials: config.WITH_CREDENTIALS,
|
||||
};
|
||||
|
||||
onCancel(() => controller.abort());
|
||||
|
||||
for (const fn of config.interceptors.request._fns) {
|
||||
requestConfig = await fn(requestConfig);
|
||||
}
|
||||
|
||||
try {
|
||||
return await axiosClient.request(requestConfig);
|
||||
} catch (error) {
|
||||
const axiosError = error as AxiosError<T>;
|
||||
if (axiosError.response) {
|
||||
return axiosError.response;
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
};
|
||||
|
||||
export const getResponseHeader = (response: AxiosResponse<unknown>, responseHeader?: string): string | undefined => {
|
||||
if (responseHeader) {
|
||||
const content = response.headers[responseHeader];
|
||||
if (isString(content)) {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const getResponseBody = (response: AxiosResponse<unknown>): unknown => {
|
||||
if (response.status !== 204) {
|
||||
return response.data;
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
|
||||
export const catchErrorCodes = (options: ApiRequestOptions, result: ApiResult): void => {
|
||||
const errors: Record<number, string> = {
|
||||
400: 'Bad Request',
|
||||
401: 'Unauthorized',
|
||||
402: 'Payment Required',
|
||||
403: 'Forbidden',
|
||||
404: 'Not Found',
|
||||
405: 'Method Not Allowed',
|
||||
406: 'Not Acceptable',
|
||||
407: 'Proxy Authentication Required',
|
||||
408: 'Request Timeout',
|
||||
409: 'Conflict',
|
||||
410: 'Gone',
|
||||
411: 'Length Required',
|
||||
412: 'Precondition Failed',
|
||||
413: 'Payload Too Large',
|
||||
414: 'URI Too Long',
|
||||
415: 'Unsupported Media Type',
|
||||
416: 'Range Not Satisfiable',
|
||||
417: 'Expectation Failed',
|
||||
418: 'Im a teapot',
|
||||
421: 'Misdirected Request',
|
||||
422: 'Unprocessable Content',
|
||||
423: 'Locked',
|
||||
424: 'Failed Dependency',
|
||||
425: 'Too Early',
|
||||
426: 'Upgrade Required',
|
||||
428: 'Precondition Required',
|
||||
429: 'Too Many Requests',
|
||||
431: 'Request Header Fields Too Large',
|
||||
451: 'Unavailable For Legal Reasons',
|
||||
500: 'Internal Server Error',
|
||||
501: 'Not Implemented',
|
||||
502: 'Bad Gateway',
|
||||
503: 'Service Unavailable',
|
||||
504: 'Gateway Timeout',
|
||||
505: 'HTTP Version Not Supported',
|
||||
506: 'Variant Also Negotiates',
|
||||
507: 'Insufficient Storage',
|
||||
508: 'Loop Detected',
|
||||
510: 'Not Extended',
|
||||
511: 'Network Authentication Required',
|
||||
...options.errors,
|
||||
}
|
||||
|
||||
const error = errors[result.status];
|
||||
if (error) {
|
||||
throw new ApiError(options, result, error);
|
||||
}
|
||||
|
||||
if (!result.ok) {
|
||||
const errorStatus = result.status ?? 'unknown';
|
||||
const errorStatusText = result.statusText ?? 'unknown';
|
||||
const errorBody = (() => {
|
||||
try {
|
||||
return JSON.stringify(result.body, null, 2);
|
||||
} catch (e) {
|
||||
return undefined;
|
||||
}
|
||||
})();
|
||||
|
||||
throw new ApiError(options, result,
|
||||
`Generic Error: status: ${errorStatus}; status text: ${errorStatusText}; body: ${errorBody}`
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Request method
|
||||
* @param config The OpenAPI configuration object
|
||||
* @param options The request options from the service
|
||||
* @param axiosClient The axios client instance to use
|
||||
* @returns CancelablePromise<T>
|
||||
* @throws ApiError
|
||||
*/
|
||||
export const request = <T>(config: OpenAPIConfig, options: ApiRequestOptions<T>, axiosClient: AxiosInstance = axios): CancelablePromise<T> => {
|
||||
return new CancelablePromise(async (resolve, reject, onCancel) => {
|
||||
try {
|
||||
const url = getUrl(config, options);
|
||||
const formData = getFormData(options);
|
||||
const body = getRequestBody(options);
|
||||
const headers = await getHeaders(config, options);
|
||||
|
||||
if (!onCancel.isCancelled) {
|
||||
let response = await sendRequest<T>(config, options, url, body, formData, headers, onCancel, axiosClient);
|
||||
|
||||
for (const fn of config.interceptors.response._fns) {
|
||||
response = await fn(response);
|
||||
}
|
||||
|
||||
const responseBody = getResponseBody(response);
|
||||
const responseHeader = getResponseHeader(response, options.responseHeader);
|
||||
|
||||
let transformedBody = responseBody;
|
||||
if (options.responseTransformer && isSuccess(response.status)) {
|
||||
transformedBody = await options.responseTransformer(responseBody)
|
||||
}
|
||||
|
||||
const result: ApiResult = {
|
||||
url,
|
||||
ok: isSuccess(response.status),
|
||||
status: response.status,
|
||||
statusText: response.statusText,
|
||||
body: responseHeader ?? transformedBody,
|
||||
};
|
||||
|
||||
catchErrorCodes(options, result);
|
||||
|
||||
resolve(result.body);
|
||||
}
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
};
|
6
frontend/src/client/index.ts
Normal file
6
frontend/src/client/index.ts
Normal file
@ -0,0 +1,6 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
export { ApiError } from './core/ApiError';
|
||||
export { CancelablePromise, CancelError } from './core/CancelablePromise';
|
||||
export { OpenAPI, type OpenAPIConfig } from './core/OpenAPI';
|
||||
export * from './sdk.gen';
|
||||
export * from './types.gen';
|
438
frontend/src/client/sdk.gen.ts
Normal file
438
frontend/src/client/sdk.gen.ts
Normal file
@ -0,0 +1,438 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
|
||||
import type { CancelablePromise } from './core/CancelablePromise';
|
||||
import { OpenAPI } from './core/OpenAPI';
|
||||
import { request as __request } from './core/request';
|
||||
import type { UserGetUserResponse, UserUpdateUserData, UserUpdateUserResponse, UserRegisterData, UserRegisterResponse, UserDeleteUserResponse, DashboardLoginAccessTokenData, DashboardLoginAccessTokenResponse, DashboardRegisterNewShopData, DashboardRegisterNewShopResponse, ShopLoginAccessTokenData, ShopLoginAccessTokenResponse, ShopDeleteUserData, ShopDeleteUserResponse, ShopLogoutResponse, ShopRegisterData, ShopRegisterResponse, ShopUpdateUserData, ShopUpdateUserResponse, UtilsHealthCheckResponse, UtilsTestDbResponse } from './types.gen';
|
||||
|
||||
export class DashboardService {
|
||||
/**
|
||||
* Get information about currently logged in user
|
||||
* @returns UserPublic Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static userGetUser(): CancelablePromise<UserGetUserResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'GET',
|
||||
url: '/user'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user details
|
||||
* @param data The data for the request.
|
||||
* @param data.requestBody
|
||||
* @returns boolean Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static userUpdateUser(data: UserUpdateUserData): CancelablePromise<UserUpdateUserResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'PUT',
|
||||
url: '/user',
|
||||
body: data.requestBody,
|
||||
mediaType: 'application/json',
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register new user
|
||||
* @param data The data for the request.
|
||||
* @param data.requestBody
|
||||
* @returns boolean Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static userRegister(data: UserRegisterData): CancelablePromise<UserRegisterResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'POST',
|
||||
url: '/user',
|
||||
body: data.requestBody,
|
||||
mediaType: 'application/json',
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete user
|
||||
* @returns boolean Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static userDeleteUser(): CancelablePromise<UserDeleteUserResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'DELETE',
|
||||
url: '/user'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Login Access Token
|
||||
* OAuth2 compatible token login for the dashboard.
|
||||
*
|
||||
* This endpoint generates an access token required for authenticating future
|
||||
* requests to the dashboard section of the application. The token is valid for
|
||||
* a predefined expiration period.
|
||||
*
|
||||
* - **username**: User's email
|
||||
* - **password**: User's password
|
||||
*
|
||||
* **Note:** This login is restricted to dashboard access only and cannot be
|
||||
* used for tenant accounts access to shops
|
||||
* @param data The data for the request.
|
||||
* @param data.formData
|
||||
* @returns Token Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static dashboardLoginAccessToken(data: DashboardLoginAccessTokenData): CancelablePromise<DashboardLoginAccessTokenResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'POST',
|
||||
url: '/login/access-token',
|
||||
formData: data.formData,
|
||||
mediaType: 'application/x-www-form-urlencoded',
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register New Shop
|
||||
* @param data The data for the request.
|
||||
* @param data.requestBody
|
||||
* @returns boolean Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static dashboardRegisterNewShop(data: DashboardRegisterNewShopData): CancelablePromise<DashboardRegisterNewShopResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'POST',
|
||||
url: '/shop',
|
||||
body: data.requestBody,
|
||||
mediaType: 'application/json',
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class LoginService {
|
||||
/**
|
||||
* Login Access Token
|
||||
* OAuth2 compatible token login for the dashboard.
|
||||
*
|
||||
* This endpoint generates an access token required for authenticating future
|
||||
* requests to the dashboard section of the application. The token is valid for
|
||||
* a predefined expiration period.
|
||||
*
|
||||
* - **username**: User's email
|
||||
* - **password**: User's password
|
||||
*
|
||||
* **Note:** This login is restricted to dashboard access only and cannot be
|
||||
* used for tenant accounts access to shops
|
||||
* @param data The data for the request.
|
||||
* @param data.formData
|
||||
* @returns Token Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static dashboardLoginAccessToken(data: DashboardLoginAccessTokenData): CancelablePromise<DashboardLoginAccessTokenResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'POST',
|
||||
url: '/login/access-token',
|
||||
formData: data.formData,
|
||||
mediaType: 'application/x-www-form-urlencoded',
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Login Access Token
|
||||
* OAuth2 compatible token login, get an access token for future requests
|
||||
* @param data The data for the request.
|
||||
* @param data.formData
|
||||
* @returns Token Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static shopLoginAccessToken(data: ShopLoginAccessTokenData): CancelablePromise<ShopLoginAccessTokenResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'POST',
|
||||
url: '/shop/{shop_uuid}/login/access-token',
|
||||
formData: data.formData,
|
||||
mediaType: 'application/x-www-form-urlencoded',
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class ShopService {
|
||||
/**
|
||||
* Login Access Token
|
||||
* OAuth2 compatible token login, get an access token for future requests
|
||||
* @param data The data for the request.
|
||||
* @param data.formData
|
||||
* @returns Token Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static shopLoginAccessToken(data: ShopLoginAccessTokenData): CancelablePromise<ShopLoginAccessTokenResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'POST',
|
||||
url: '/shop/{shop_uuid}/login/access-token',
|
||||
formData: data.formData,
|
||||
mediaType: 'application/x-www-form-urlencoded',
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete user
|
||||
* @param data The data for the request.
|
||||
* @param data.shopUuid
|
||||
* @returns unknown Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static shopDeleteUser(data: ShopDeleteUserData): CancelablePromise<ShopDeleteUserResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'DELETE',
|
||||
url: '/shop/{shop_uuid}/user/delete',
|
||||
path: {
|
||||
shop_uuid: data.shopUuid
|
||||
},
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* User logout
|
||||
* @returns unknown Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static shopLogout(): CancelablePromise<ShopLogoutResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'DELETE',
|
||||
url: '/shop/{shop_uuid}/user/logout'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register new user
|
||||
* @param data The data for the request.
|
||||
* @param data.shopUuid
|
||||
* @param data.requestBody
|
||||
* @returns unknown Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static shopRegister(data: ShopRegisterData): CancelablePromise<ShopRegisterResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'POST',
|
||||
url: '/shop/{shop_uuid}/user/register',
|
||||
path: {
|
||||
shop_uuid: data.shopUuid
|
||||
},
|
||||
body: data.requestBody,
|
||||
mediaType: 'application/json',
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user details
|
||||
* @param data The data for the request.
|
||||
* @param data.requestBody
|
||||
* @returns unknown Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static shopUpdateUser(data: ShopUpdateUserData): CancelablePromise<ShopUpdateUserResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'PUT',
|
||||
url: '/shop/{shop_uuid}/user/update',
|
||||
body: data.requestBody,
|
||||
mediaType: 'application/json',
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class UserService {
|
||||
/**
|
||||
* Get information about currently logged in user
|
||||
* @returns UserPublic Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static userGetUser(): CancelablePromise<UserGetUserResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'GET',
|
||||
url: '/user'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user details
|
||||
* @param data The data for the request.
|
||||
* @param data.requestBody
|
||||
* @returns boolean Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static userUpdateUser(data: UserUpdateUserData): CancelablePromise<UserUpdateUserResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'PUT',
|
||||
url: '/user',
|
||||
body: data.requestBody,
|
||||
mediaType: 'application/json',
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register new user
|
||||
* @param data The data for the request.
|
||||
* @param data.requestBody
|
||||
* @returns boolean Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static userRegister(data: UserRegisterData): CancelablePromise<UserRegisterResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'POST',
|
||||
url: '/user',
|
||||
body: data.requestBody,
|
||||
mediaType: 'application/json',
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete user
|
||||
* @returns boolean Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static userDeleteUser(): CancelablePromise<UserDeleteUserResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'DELETE',
|
||||
url: '/user'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete user
|
||||
* @param data The data for the request.
|
||||
* @param data.shopUuid
|
||||
* @returns unknown Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static shopDeleteUser(data: ShopDeleteUserData): CancelablePromise<ShopDeleteUserResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'DELETE',
|
||||
url: '/shop/{shop_uuid}/user/delete',
|
||||
path: {
|
||||
shop_uuid: data.shopUuid
|
||||
},
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* User logout
|
||||
* @returns unknown Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static shopLogout(): CancelablePromise<ShopLogoutResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'DELETE',
|
||||
url: '/shop/{shop_uuid}/user/logout'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Register new user
|
||||
* @param data The data for the request.
|
||||
* @param data.shopUuid
|
||||
* @param data.requestBody
|
||||
* @returns unknown Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static shopRegister(data: ShopRegisterData): CancelablePromise<ShopRegisterResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'POST',
|
||||
url: '/shop/{shop_uuid}/user/register',
|
||||
path: {
|
||||
shop_uuid: data.shopUuid
|
||||
},
|
||||
body: data.requestBody,
|
||||
mediaType: 'application/json',
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Update user details
|
||||
* @param data The data for the request.
|
||||
* @param data.requestBody
|
||||
* @returns unknown Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static shopUpdateUser(data: ShopUpdateUserData): CancelablePromise<ShopUpdateUserResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'PUT',
|
||||
url: '/shop/{shop_uuid}/user/update',
|
||||
body: data.requestBody,
|
||||
mediaType: 'application/json',
|
||||
errors: {
|
||||
422: 'Validation Error'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export class UtilsService {
|
||||
/**
|
||||
* Health Check
|
||||
* Ping the API whether it's alive or not
|
||||
* @returns boolean Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static utilsHealthCheck(): CancelablePromise<UtilsHealthCheckResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'GET',
|
||||
url: '/utils/health-check/'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test Db
|
||||
* Ping database using select 1 to see if connection works
|
||||
* @returns boolean Successful Response
|
||||
* @throws ApiError
|
||||
*/
|
||||
public static utilsTestDb(): CancelablePromise<UtilsTestDbResponse> {
|
||||
return __request(OpenAPI, {
|
||||
method: 'GET',
|
||||
url: '/utils/test-db/'
|
||||
});
|
||||
}
|
||||
|
||||
}
|
142
frontend/src/client/types.gen.ts
Normal file
142
frontend/src/client/types.gen.ts
Normal file
@ -0,0 +1,142 @@
|
||||
// This file is auto-generated by @hey-api/openapi-ts
|
||||
|
||||
export type Body_Dashboard_login_access_token = {
|
||||
grant_type?: (string | null);
|
||||
username: string;
|
||||
password: string;
|
||||
scope?: string;
|
||||
client_id?: (string | null);
|
||||
client_secret?: (string | null);
|
||||
};
|
||||
|
||||
export type Body_Shop_login_access_token = {
|
||||
grant_type?: (string | null);
|
||||
username: string;
|
||||
password: string;
|
||||
scope?: string;
|
||||
client_id?: (string | null);
|
||||
client_secret?: (string | null);
|
||||
};
|
||||
|
||||
export type HTTPValidationError = {
|
||||
detail?: Array<ValidationError>;
|
||||
};
|
||||
|
||||
export type ShopAddress = {
|
||||
street: string;
|
||||
city: string;
|
||||
state: string;
|
||||
postal_code: string;
|
||||
country: string;
|
||||
};
|
||||
|
||||
export type ShopCreate = {
|
||||
name: string;
|
||||
description: string;
|
||||
currency: string;
|
||||
contact_email: string;
|
||||
contact_phone_number: string;
|
||||
address: ShopAddress;
|
||||
};
|
||||
|
||||
export type Token = {
|
||||
access_token: string;
|
||||
token_type?: string;
|
||||
};
|
||||
|
||||
export type UserPublic = {
|
||||
uuid: string;
|
||||
username: string;
|
||||
email: string;
|
||||
first_name: (string | null);
|
||||
last_name: (string | null);
|
||||
phone_number: string;
|
||||
};
|
||||
|
||||
export type UserRegister = {
|
||||
username: string;
|
||||
email: string;
|
||||
phone_number: string;
|
||||
/**
|
||||
* Password must conform to this regex:
|
||||
* ```
|
||||
* ^(?=.*?[A-Z])(?=.*?[a-z])(?=.*?[0-9])(?=.*?[#?!@$ %^&*-]).{8,128}$
|
||||
* ```
|
||||
*/
|
||||
password: string;
|
||||
};
|
||||
|
||||
export type UserUpdate = {
|
||||
email: (string | null);
|
||||
phone_number: (string | null);
|
||||
username: (string | null);
|
||||
first_name?: (string | null);
|
||||
last_name?: (string | null);
|
||||
};
|
||||
|
||||
export type ValidationError = {
|
||||
loc: Array<(string | number)>;
|
||||
msg: string;
|
||||
type: string;
|
||||
};
|
||||
|
||||
export type UserGetUserResponse = (UserPublic);
|
||||
|
||||
export type UserUpdateUserData = {
|
||||
requestBody: UserUpdate;
|
||||
};
|
||||
|
||||
export type UserUpdateUserResponse = (boolean);
|
||||
|
||||
export type UserRegisterData = {
|
||||
requestBody: UserRegister;
|
||||
};
|
||||
|
||||
export type UserRegisterResponse = (boolean);
|
||||
|
||||
export type UserDeleteUserResponse = (boolean);
|
||||
|
||||
export type DashboardLoginAccessTokenData = {
|
||||
formData: Body_Dashboard_login_access_token;
|
||||
};
|
||||
|
||||
export type DashboardLoginAccessTokenResponse = (Token);
|
||||
|
||||
export type DashboardRegisterNewShopData = {
|
||||
requestBody: ShopCreate;
|
||||
};
|
||||
|
||||
export type DashboardRegisterNewShopResponse = (boolean);
|
||||
|
||||
export type ShopLoginAccessTokenData = {
|
||||
formData: Body_Shop_login_access_token;
|
||||
};
|
||||
|
||||
export type ShopLoginAccessTokenResponse = (Token);
|
||||
|
||||
export type ShopDeleteUserData = {
|
||||
shopUuid: unknown;
|
||||
};
|
||||
|
||||
export type ShopDeleteUserResponse = (unknown);
|
||||
|
||||
export type ShopLogoutResponse = (unknown);
|
||||
|
||||
export type ShopRegisterData = {
|
||||
requestBody: UserRegister;
|
||||
shopUuid: unknown;
|
||||
};
|
||||
|
||||
export type ShopRegisterResponse = (unknown);
|
||||
|
||||
export type ShopUpdateUserData = {
|
||||
requestBody: {
|
||||
[key: string]: unknown;
|
||||
};
|
||||
};
|
||||
|
||||
export type ShopUpdateUserResponse = (unknown);
|
||||
|
||||
export type UtilsHealthCheckResponse = (boolean);
|
||||
|
||||
export type UtilsTestDbResponse = (boolean);
|
@ -1,175 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import {
|
||||
AudioWaveform,
|
||||
BookOpen,
|
||||
Bot,
|
||||
Command,
|
||||
Frame,
|
||||
GalleryVerticalEnd,
|
||||
Map,
|
||||
PieChart,
|
||||
Settings2,
|
||||
SquareTerminal
|
||||
} from "lucide-react";
|
||||
|
||||
import { NavMain } from "@/components/nav-main";
|
||||
import { NavProjects } from "@/components/nav-projects";
|
||||
import { NavUser } from "@/components/nav-user";
|
||||
import { TeamSwitcher } from "@/components/team-switcher";
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarFooter,
|
||||
SidebarHeader,
|
||||
SidebarRail
|
||||
} from "@/components/ui/sidebar";
|
||||
|
||||
// This is sample data.
|
||||
const data = {
|
||||
user: {
|
||||
name: "shadcn",
|
||||
email: "m@example.com",
|
||||
avatar: "/avatars/shadcn.jpg"
|
||||
},
|
||||
teams: [
|
||||
{
|
||||
name: "Acme Inc",
|
||||
logo: GalleryVerticalEnd,
|
||||
plan: "Enterprise"
|
||||
},
|
||||
{
|
||||
name: "Acme Corp.",
|
||||
logo: AudioWaveform,
|
||||
plan: "Startup"
|
||||
},
|
||||
{
|
||||
name: "Evil Corp.",
|
||||
logo: Command,
|
||||
plan: "Free"
|
||||
}
|
||||
],
|
||||
navMain: [
|
||||
{
|
||||
title: "Playground",
|
||||
url: "#",
|
||||
icon: SquareTerminal,
|
||||
isActive: true,
|
||||
items: [
|
||||
{
|
||||
title: "History",
|
||||
url: "#"
|
||||
},
|
||||
{
|
||||
title: "Starred",
|
||||
url: "#"
|
||||
},
|
||||
{
|
||||
title: "Settings",
|
||||
url: "#"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Models",
|
||||
url: "#",
|
||||
icon: Bot,
|
||||
items: [
|
||||
{
|
||||
title: "Genesis",
|
||||
url: "#"
|
||||
},
|
||||
{
|
||||
title: "Explorer",
|
||||
url: "#"
|
||||
},
|
||||
{
|
||||
title: "Quantum",
|
||||
url: "#"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Documentation",
|
||||
url: "#",
|
||||
icon: BookOpen,
|
||||
items: [
|
||||
{
|
||||
title: "Introduction",
|
||||
url: "#"
|
||||
},
|
||||
{
|
||||
title: "Get Started",
|
||||
url: "#"
|
||||
},
|
||||
{
|
||||
title: "Tutorials",
|
||||
url: "#"
|
||||
},
|
||||
{
|
||||
title: "Changelog",
|
||||
url: "#"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Settings",
|
||||
url: "#",
|
||||
icon: Settings2,
|
||||
items: [
|
||||
{
|
||||
title: "General",
|
||||
url: "#"
|
||||
},
|
||||
{
|
||||
title: "Team",
|
||||
url: "#"
|
||||
},
|
||||
{
|
||||
title: "Billing",
|
||||
url: "#"
|
||||
},
|
||||
{
|
||||
title: "Limits",
|
||||
url: "#"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
projects: [
|
||||
{
|
||||
name: "Design Engineering",
|
||||
url: "#",
|
||||
icon: Frame
|
||||
},
|
||||
{
|
||||
name: "Sales & Marketing",
|
||||
url: "#",
|
||||
icon: PieChart
|
||||
},
|
||||
{
|
||||
name: "Travel",
|
||||
url: "#",
|
||||
icon: Map
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||
return (
|
||||
<Sidebar collapsible="icon" {...props}>
|
||||
<SidebarHeader>
|
||||
<TeamSwitcher teams={data.teams} />
|
||||
</SidebarHeader>
|
||||
<SidebarContent>
|
||||
<NavMain items={data.navMain} />
|
||||
<NavProjects projects={data.projects} />
|
||||
</SidebarContent>
|
||||
<SidebarFooter>
|
||||
<NavUser user={data.user} />
|
||||
</SidebarFooter>
|
||||
<SidebarRail />
|
||||
</Sidebar>
|
||||
);
|
||||
}
|
32
frontend/src/components/dynamic-login-button.tsx
Normal file
32
frontend/src/components/dynamic-login-button.tsx
Normal file
@ -0,0 +1,32 @@
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import { Button } from "./ui/button";
|
||||
import useAuth from "@/hooks/useAuth";
|
||||
|
||||
const DynamicLoginButton = () => {
|
||||
const { logout, user } = useAuth();
|
||||
if (user) {
|
||||
return (
|
||||
<>
|
||||
<Button variant="secondary" className="hidden px-2 md:block">
|
||||
<Link to="/dashboard">Dashboard</Link>
|
||||
</Button>
|
||||
<Button className="ml-2 mr-2 hidden md:block" onClick={logout}>
|
||||
Logout
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<Button variant="secondary" className="hidden px-2 md:block">
|
||||
<Link to="/sign-in">Login</Link>
|
||||
</Button>
|
||||
<Button className="ml-2 mr-2 hidden md:block">
|
||||
<Link to="/sign-up">Get Started</Link>
|
||||
</Button>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default DynamicLoginButton;
|
@ -1,29 +1,33 @@
|
||||
import {
|
||||
Sidebar,
|
||||
SidebarContent,
|
||||
SidebarFooter,
|
||||
SidebarHeader,
|
||||
SidebarRail
|
||||
} from "@/components/ui/sidebar";
|
||||
import { NavGroup } from "@/components/layout/nav-group";
|
||||
import { NavUser } from "@/components/layout/nav-user";
|
||||
import { TeamSwitcher } from "@/components/layout/team-switcher";
|
||||
import { sidebarData } from "./data/sidebar-data";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
|
||||
return (
|
||||
<Sidebar collapsible="icon" variant="floating" {...props}>
|
||||
<SidebarHeader>
|
||||
<TeamSwitcher teams={sidebarData.teams} />
|
||||
<h1
|
||||
className={cn(
|
||||
"header-fixed peer/header flex h-16 w-[inherit] items-center gap-3 rounded-md bg-background p-4 text-xl font-bold sm:gap-4"
|
||||
)}
|
||||
{...props}>
|
||||
SwagShop
|
||||
</h1>
|
||||
</SidebarHeader>
|
||||
<SidebarContent>
|
||||
{sidebarData.navGroups.map((props) => (
|
||||
<NavGroup key={props.title} {...props} />
|
||||
))}
|
||||
</SidebarContent>
|
||||
<SidebarFooter>
|
||||
{/* <SidebarFooter>
|
||||
<NavUser user={sidebarData.user} />
|
||||
</SidebarFooter>
|
||||
</SidebarFooter> */}
|
||||
<SidebarRail />
|
||||
</Sidebar>
|
||||
);
|
||||
|
@ -1,22 +1,17 @@
|
||||
import {
|
||||
IconBarrierBlock,
|
||||
IconBrowserCheck,
|
||||
IconBug,
|
||||
IconChecklist,
|
||||
IconError404,
|
||||
IconCoin,
|
||||
IconForklift,
|
||||
IconHelp,
|
||||
IconLayoutDashboard,
|
||||
IconLock,
|
||||
IconLockAccess,
|
||||
IconMessages,
|
||||
IconNotification,
|
||||
IconPackages,
|
||||
IconPackage,
|
||||
IconPalette,
|
||||
IconServerOff,
|
||||
IconPercentage,
|
||||
IconSettings,
|
||||
IconTag,
|
||||
IconTool,
|
||||
IconUserCog,
|
||||
IconUserOff,
|
||||
IconUsers
|
||||
} from "@tabler/icons-react";
|
||||
import { AudioWaveform, Command, GalleryVerticalEnd } from "lucide-react";
|
||||
@ -47,100 +42,43 @@ export const sidebarData: SidebarData = {
|
||||
],
|
||||
navGroups: [
|
||||
{
|
||||
title: "General",
|
||||
title: "Dashboard",
|
||||
items: [
|
||||
{
|
||||
title: "Dashboard",
|
||||
url: "/",
|
||||
url: "/dashboard",
|
||||
icon: IconLayoutDashboard
|
||||
},
|
||||
{
|
||||
title: "Tasks",
|
||||
url: "/tasks",
|
||||
icon: IconChecklist
|
||||
title: "Products",
|
||||
url: "/dashboard/products",
|
||||
icon: IconPackage
|
||||
},
|
||||
{
|
||||
title: "Apps",
|
||||
url: "/apps",
|
||||
icon: IconPackages
|
||||
title: "Inventory",
|
||||
url: "/dashboard/tasks",
|
||||
icon: IconForklift
|
||||
},
|
||||
{
|
||||
title: "Chats",
|
||||
url: "/chats",
|
||||
badge: "3",
|
||||
icon: IconMessages
|
||||
title: "Sales",
|
||||
icon: IconCoin,
|
||||
items: [
|
||||
{
|
||||
title: "Discounts",
|
||||
url: "/dashboard/sales/discounts",
|
||||
icon: IconPercentage
|
||||
},
|
||||
{
|
||||
title: "Users",
|
||||
url: "/users",
|
||||
title: "Coupons",
|
||||
url: "/dashboard/sales/coupons",
|
||||
icon: IconTag
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Customers",
|
||||
url: "/dashboard/users",
|
||||
icon: IconUsers
|
||||
},
|
||||
{
|
||||
title: "NBA",
|
||||
url: "/nba",
|
||||
icon: IconChecklist
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Pages",
|
||||
items: [
|
||||
{
|
||||
title: "Auth",
|
||||
icon: IconLockAccess,
|
||||
items: [
|
||||
{
|
||||
title: "Sign In",
|
||||
url: "/sign-in"
|
||||
},
|
||||
{
|
||||
title: "Sign In (2 Col)",
|
||||
url: "/sign-in-2"
|
||||
},
|
||||
{
|
||||
title: "Sign Up",
|
||||
url: "/sign-up"
|
||||
},
|
||||
{
|
||||
title: "Forgot Password",
|
||||
url: "/forgot-password"
|
||||
},
|
||||
{
|
||||
title: "OTP",
|
||||
url: "/otp"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
title: "Errors",
|
||||
icon: IconBug,
|
||||
items: [
|
||||
{
|
||||
title: "Unauthorized",
|
||||
url: "/401",
|
||||
icon: IconLock
|
||||
},
|
||||
{
|
||||
title: "Forbidden",
|
||||
url: "/403",
|
||||
icon: IconUserOff
|
||||
},
|
||||
{
|
||||
title: "Not Found",
|
||||
url: "/404",
|
||||
icon: IconError404
|
||||
},
|
||||
{
|
||||
title: "Internal Server Error",
|
||||
url: "/500",
|
||||
icon: IconServerOff
|
||||
},
|
||||
{
|
||||
title: "Maintenance Error",
|
||||
url: "/503",
|
||||
icon: IconBarrierBlock
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
@ -153,27 +91,27 @@ export const sidebarData: SidebarData = {
|
||||
items: [
|
||||
{
|
||||
title: "Profile",
|
||||
url: "/settings",
|
||||
url: "/dashboard/settings",
|
||||
icon: IconUserCog
|
||||
},
|
||||
{
|
||||
title: "Account",
|
||||
url: "/settings/account",
|
||||
url: "/dashboard/settings/account",
|
||||
icon: IconTool
|
||||
},
|
||||
{
|
||||
title: "Appearance",
|
||||
url: "/settings/appearance",
|
||||
url: "/dashboard/settings/appearance",
|
||||
icon: IconPalette
|
||||
},
|
||||
{
|
||||
title: "Notifications",
|
||||
url: "/settings/notifications",
|
||||
url: "/dashboard/settings/notifications",
|
||||
icon: IconNotification
|
||||
},
|
||||
{
|
||||
title: "Display",
|
||||
url: "/settings/display",
|
||||
url: "/dashboard/settings/display",
|
||||
icon: IconBrowserCheck
|
||||
}
|
||||
]
|
||||
|
@ -8,7 +8,7 @@ import { Menu } from "lucide-react";
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { ThemeSwitch } from "./theme-switch";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import DynamicLoginButton from "./dynamic-login-button";
|
||||
|
||||
const MainNavbar = () => {
|
||||
return (
|
||||
@ -27,11 +27,7 @@ const MainNavbar = () => {
|
||||
</ul>
|
||||
|
||||
<div className="flex items-center">
|
||||
<Button variant="secondary" className="hidden px-2 md:block">
|
||||
<Link to="/sign-in">Login</Link>
|
||||
</Button>
|
||||
<Button className="ml-2 mr-2 hidden md:block"><Link to="/sign-up">Get Started</Link></Button>
|
||||
|
||||
<DynamicLoginButton />
|
||||
<div className="mr-2 flex items-center gap-2 md:hidden">
|
||||
|
||||
<DropdownMenu>
|
||||
|
@ -11,51 +11,55 @@ import {
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuTrigger
|
||||
} from "@/components/ui/dropdown-menu";
|
||||
import useAuth from "@/hooks/useAuth";
|
||||
|
||||
export function ProfileDropdown() {
|
||||
const { user, logout } = useAuth();
|
||||
if (!user) return "";
|
||||
|
||||
let shorthandUsername = "";
|
||||
if (user.first_name && user.last_name) {
|
||||
shorthandUsername = (user.first_name[0] + user.last_name[0]).toUpperCase();
|
||||
} else {
|
||||
shorthandUsername = user.username[0].toUpperCase();
|
||||
}
|
||||
|
||||
return (
|
||||
<DropdownMenu modal={false}>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<Button variant="ghost" className="relative h-8 w-8 rounded-full">
|
||||
<Avatar className="h-8 w-8">
|
||||
<AvatarImage src="/avatars/01.png" alt="@shadcn" />
|
||||
<AvatarFallback>SN</AvatarFallback>
|
||||
<AvatarFallback>{shorthandUsername}</AvatarFallback>
|
||||
</Avatar>
|
||||
</Button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent className="w-56" align="end" forceMount>
|
||||
<DropdownMenuLabel className="font-normal">
|
||||
<div className="flex flex-col space-y-1">
|
||||
<p className="text-sm font-medium leading-none">satnaing</p>
|
||||
<p className="text-sm font-medium leading-none">{user.username}</p>
|
||||
<p className="text-xs leading-none text-muted-foreground">
|
||||
satnaingdev@gmail.com
|
||||
{user.email}
|
||||
</p>
|
||||
</div>
|
||||
</DropdownMenuLabel>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuGroup>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link to="/settings">
|
||||
<Link to="/dashboard/settings">
|
||||
Profile
|
||||
<DropdownMenuShortcut>⇧⌘P</DropdownMenuShortcut>
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link to="/settings">
|
||||
Billing
|
||||
<DropdownMenuShortcut>⌘B</DropdownMenuShortcut>
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem asChild>
|
||||
<Link to="/settings">
|
||||
<Link to="/dashboard/settings">
|
||||
Settings
|
||||
<DropdownMenuShortcut>⌘S</DropdownMenuShortcut>
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem>New Team</DropdownMenuItem>
|
||||
</DropdownMenuGroup>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={logout}>
|
||||
Log out
|
||||
<DropdownMenuShortcut>⇧⌘Q</DropdownMenuShortcut>
|
||||
</DropdownMenuItem>
|
||||
|
@ -7,7 +7,7 @@ const Input = React.forwardRef<HTMLInputElement, React.ComponentProps<"input">>(
|
||||
<input
|
||||
type={type}
|
||||
className={cn(
|
||||
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
"flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
||||
className
|
||||
)}
|
||||
ref={ref}
|
||||
|
167
frontend/src/components/ui/phone-number-input.tsx
Normal file
167
frontend/src/components/ui/phone-number-input.tsx
Normal file
@ -0,0 +1,167 @@
|
||||
import * as React from "react";
|
||||
import { CheckIcon, ChevronsUpDown } from "lucide-react";
|
||||
import * as RPNInput from "react-phone-number-input";
|
||||
import flags from "react-phone-number-input/flags";
|
||||
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList
|
||||
} from "@/components/ui/command";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger
|
||||
} from "@/components/ui/popover";
|
||||
import { ScrollArea } from "@/components/ui/scroll-area";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
type PhoneInputProps = Omit<
|
||||
React.ComponentProps<"input">,
|
||||
"onChange" | "value" | "ref"
|
||||
> &
|
||||
Omit<RPNInput.Props<typeof RPNInput.default>, "onChange"> & {
|
||||
onChange?: (value: RPNInput.Value) => void;
|
||||
};
|
||||
|
||||
const PhoneInput: React.ForwardRefExoticComponent<PhoneInputProps> =
|
||||
React.forwardRef<React.ElementRef<typeof RPNInput.default>, PhoneInputProps>(
|
||||
({ className, onChange, ...props }, ref) => {
|
||||
return (
|
||||
<RPNInput.default
|
||||
ref={ref}
|
||||
className={cn("flex", className)}
|
||||
flagComponent={FlagComponent}
|
||||
countrySelectComponent={CountrySelect}
|
||||
inputComponent={InputComponent}
|
||||
smartCaret={false}
|
||||
/**
|
||||
* Handles the onChange event.
|
||||
*
|
||||
* react-phone-number-input might trigger the onChange event as undefined
|
||||
* when a valid phone number is not entered. To prevent this,
|
||||
* the value is coerced to an empty string.
|
||||
*
|
||||
* @param {E164Number | undefined} value - The entered value
|
||||
*/
|
||||
onChange={(value) => onChange?.(value || ("" as RPNInput.Value))}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
PhoneInput.displayName = "PhoneInput";
|
||||
|
||||
const InputComponent = React.forwardRef<
|
||||
HTMLInputElement,
|
||||
React.ComponentProps<"input">
|
||||
>(({ className, ...props }, ref) => (
|
||||
<Input
|
||||
className={cn("rounded-e-lg rounded-s-none", className)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
));
|
||||
InputComponent.displayName = "InputComponent";
|
||||
|
||||
type CountryEntry = { label: string; value: RPNInput.Country | undefined };
|
||||
|
||||
type CountrySelectProps = {
|
||||
disabled?: boolean;
|
||||
value: RPNInput.Country;
|
||||
options: CountryEntry[];
|
||||
onChange: (country: RPNInput.Country) => void;
|
||||
};
|
||||
|
||||
const CountrySelect = ({
|
||||
disabled,
|
||||
value: selectedCountry,
|
||||
options: countryList,
|
||||
onChange
|
||||
}: CountrySelectProps) => {
|
||||
return (
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
className="flex gap-1 rounded-e-none rounded-s-lg border-r-0 px-3 focus:z-10"
|
||||
disabled={disabled}>
|
||||
<FlagComponent
|
||||
country={selectedCountry}
|
||||
countryName={selectedCountry}
|
||||
/>
|
||||
<ChevronsUpDown
|
||||
className={cn(
|
||||
"-mr-2 size-4 opacity-50",
|
||||
disabled ? "hidden" : "opacity-100"
|
||||
)}
|
||||
/>
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[300px] p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="Search country..." />
|
||||
<CommandList>
|
||||
<ScrollArea className="h-72">
|
||||
<CommandEmpty>No country found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{countryList.map(({ value, label }) =>
|
||||
value ? (
|
||||
<CountrySelectOption
|
||||
key={value}
|
||||
country={value}
|
||||
countryName={label}
|
||||
selectedCountry={selectedCountry}
|
||||
onChange={onChange}
|
||||
/>
|
||||
) : null
|
||||
)}
|
||||
</CommandGroup>
|
||||
</ScrollArea>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
interface CountrySelectOptionProps extends RPNInput.FlagProps {
|
||||
selectedCountry: RPNInput.Country;
|
||||
onChange: (country: RPNInput.Country) => void;
|
||||
}
|
||||
|
||||
const CountrySelectOption = ({
|
||||
country,
|
||||
countryName,
|
||||
selectedCountry,
|
||||
onChange
|
||||
}: CountrySelectOptionProps) => {
|
||||
return (
|
||||
<CommandItem className="gap-2" onSelect={() => onChange(country)}>
|
||||
<FlagComponent country={country} countryName={countryName} />
|
||||
<span className="flex-1 text-sm">{countryName}</span>
|
||||
<span className="text-sm text-foreground/50">{`+${RPNInput.getCountryCallingCode(country)}`}</span>
|
||||
<CheckIcon
|
||||
className={`ml-auto size-4 ${country === selectedCountry ? "opacity-100" : "opacity-0"}`}
|
||||
/>
|
||||
</CommandItem>
|
||||
);
|
||||
};
|
||||
|
||||
const FlagComponent = ({ country, countryName }: RPNInput.FlagProps) => {
|
||||
const Flag = flags[country];
|
||||
|
||||
return (
|
||||
<span className="flex h-4 w-6 overflow-hidden rounded-sm bg-foreground/20 [&_svg]:size-full">
|
||||
{Flag && <Flag title={countryName} />}
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export { PhoneInput };
|
@ -4,7 +4,7 @@ import { VisuallyHidden } from "@radix-ui/react-visually-hidden";
|
||||
import { VariantProps, cva } from "class-variance-authority";
|
||||
import { PanelLeft } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { useIsMobile } from "@/hooks/use-mobile";
|
||||
import { useIsMobile } from "@/hooks/useMobile";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
|
@ -1,69 +1,105 @@
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"
|
||||
import { useNavigate } from "@tanstack/react-router"
|
||||
import { useState } from "react"
|
||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { useNavigate } from "@tanstack/react-router";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
import { handleServerError } from "@/utils/handle-server-error"
|
||||
import { handleServerError } from "@/utils/handle-server-error";
|
||||
import { ApiError } from "@/errors/api-error";
|
||||
import {
|
||||
DashboardService,
|
||||
LoginService,
|
||||
ShopLoginAccessTokenData,
|
||||
UserPublic,
|
||||
UserRegister,
|
||||
UserService,
|
||||
UserUpdate
|
||||
} from "@/client";
|
||||
import { toast } from "./useToast";
|
||||
|
||||
const isLoggedIn = () => {
|
||||
return localStorage.getItem("access_token") !== null
|
||||
}
|
||||
return localStorage.getItem("access_token") !== null;
|
||||
};
|
||||
|
||||
const useAuth = () => {
|
||||
const [error, setError] = useState<string | null>(null)
|
||||
const navigate = useNavigate()
|
||||
const queryClient = useQueryClient()
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [loggedIn, setLoggedIn] = useState(isLoggedIn());
|
||||
const navigate = useNavigate();
|
||||
const queryClient = useQueryClient();
|
||||
const { data: user } = useQuery<UserPublic | null, Error>({
|
||||
queryKey: ["currentUser"],
|
||||
queryFn: UsersService.readUserMe,
|
||||
enabled: isLoggedIn(),
|
||||
})
|
||||
queryFn: DashboardService.userGetUser,
|
||||
enabled: loggedIn
|
||||
});
|
||||
|
||||
const signUpMutation = useMutation({
|
||||
mutationFn: (data: UserRegister) =>
|
||||
UsersService.registerUser({ requestBody: data }),
|
||||
DashboardService.userRegister({ requestBody: data }),
|
||||
onSuccess: () => navigate({ to: "/sign-in" }),
|
||||
onError: (err: ApiError) => handleServerError(err),
|
||||
onSettled: () => queryClient.invalidateQueries({ queryKey: ["users"] })
|
||||
});
|
||||
|
||||
onSuccess: () => {
|
||||
navigate({ to: "/sign-in" })
|
||||
},
|
||||
onError: (err: ApiError) => {
|
||||
handleServerError(err)
|
||||
},
|
||||
onSettled: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["users"] })
|
||||
},
|
||||
})
|
||||
|
||||
const login = async (data: AccessToken) => {
|
||||
const response = await LoginService.loginAccessToken({
|
||||
formData: data,
|
||||
})
|
||||
localStorage.setItem("access_token", response.access_token)
|
||||
const login = async (data: ShopLoginAccessTokenData) => {
|
||||
const response = await LoginService.dashboardLoginAccessToken({
|
||||
formData: {
|
||||
username: data.formData.username,
|
||||
password: data.formData.password
|
||||
}
|
||||
});
|
||||
localStorage.setItem("access_token", response.access_token);
|
||||
setLoggedIn(true);
|
||||
await queryClient.invalidateQueries({ queryKey: ["currentUser"] });
|
||||
};
|
||||
|
||||
const loginMutation = useMutation({
|
||||
mutationFn: login,
|
||||
onSuccess: () => {
|
||||
navigate({ to: "/" })
|
||||
},
|
||||
onError: (err: ApiError) => {
|
||||
handleError(err)
|
||||
},
|
||||
})
|
||||
onSuccess: () => navigate({ to: "/" }),
|
||||
onError: (err: ApiError) => handleServerError(err)
|
||||
});
|
||||
|
||||
const logout = () => {
|
||||
localStorage.removeItem("access_token")
|
||||
navigate({ to: "/sign-in" })
|
||||
localStorage.removeItem("access_token");
|
||||
setLoggedIn(false);
|
||||
queryClient.invalidateQueries({ queryKey: ["currentUser"] });
|
||||
navigate({ to: "/", replace: true, reloadDocument: true });
|
||||
};
|
||||
|
||||
const updateAccountMutation = useMutation({
|
||||
mutationFn: (data: UserUpdate) =>
|
||||
UserService.userUpdateUser({ requestBody: data }),
|
||||
onSuccess: () => {
|
||||
toast({ title: "Account updated successfully" });
|
||||
queryClient.invalidateQueries({ queryKey: ["currentUser"] });
|
||||
},
|
||||
onError: (err: ApiError) => handleServerError(err)
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const handleStorageChange = (event: StorageEvent) => {
|
||||
if (event.key === "access_token") {
|
||||
const tokenExists = event.newValue !== null;
|
||||
setLoggedIn(tokenExists);
|
||||
if (!tokenExists) {
|
||||
queryClient.removeQueries({ queryKey: ["currentUser"] });
|
||||
} else {
|
||||
queryClient.invalidateQueries({ queryKey: ["currentUser"] });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("storage", handleStorageChange);
|
||||
return () => window.removeEventListener("storage", handleStorageChange);
|
||||
}, [queryClient]);
|
||||
|
||||
return {
|
||||
signUpMutation,
|
||||
loginMutation,
|
||||
updateAccountMutation,
|
||||
logout,
|
||||
user,
|
||||
error,
|
||||
resetError: () => setError(null),
|
||||
}
|
||||
}
|
||||
resetError: () => setError(null)
|
||||
};
|
||||
};
|
||||
|
||||
export { isLoggedIn }
|
||||
export default useAuth
|
||||
export { isLoggedIn };
|
||||
export default useAuth;
|
||||
|
@ -15,6 +15,12 @@ import { ThemeProvider } from "./context/theme-context";
|
||||
import "./index.css";
|
||||
// Generated Routes
|
||||
import { routeTree } from "./routeTree.gen";
|
||||
import { OpenAPI } from "./client";
|
||||
|
||||
OpenAPI.BASE = import.meta.env.VITE_API_URL;
|
||||
OpenAPI.TOKEN = async () => {
|
||||
return localStorage.getItem("access_token") ?? "";
|
||||
};
|
||||
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: {
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { HTMLAttributes, useState } from "react";
|
||||
import { HTMLAttributes } from "react";
|
||||
import { z } from "zod";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
@ -15,6 +15,7 @@ import {
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { PasswordInput } from "@/components/password-input";
|
||||
import useAuth from "@/hooks/useAuth";
|
||||
|
||||
type UserAuthFormProps = HTMLAttributes<HTMLDivElement>;
|
||||
|
||||
@ -34,7 +35,7 @@ const formSchema = z.object({
|
||||
});
|
||||
|
||||
export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const { loginMutation, resetError } = useAuth();
|
||||
|
||||
const form = useForm<z.infer<typeof formSchema>>({
|
||||
resolver: zodResolver(formSchema),
|
||||
@ -44,13 +45,13 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
|
||||
}
|
||||
});
|
||||
|
||||
function onSubmit(data: z.infer<typeof formSchema>) {
|
||||
setIsLoading(true);
|
||||
console.log(data);
|
||||
|
||||
setTimeout(() => {
|
||||
setIsLoading(false);
|
||||
}, 3000);
|
||||
async function onSubmit(data: z.infer<typeof formSchema>) {
|
||||
resetError();
|
||||
try {
|
||||
await loginMutation.mutateAsync({formData: {username: data.email, password: data.password}});
|
||||
} catch {
|
||||
// Error handled in useAuth hook
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
@ -91,8 +92,8 @@ export function UserAuthForm({ className, ...props }: UserAuthFormProps) {
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button className="mt-2" disabled={isLoading}>
|
||||
Login
|
||||
<Button className="mt-2" disabled={loginMutation.isPending}>
|
||||
{loginMutation.isPending ? "Logging in..." : "Login"}
|
||||
</Button>
|
||||
|
||||
<div className="relative my-2">
|
||||
|
@ -16,6 +16,8 @@ import { Input } from "@/components/ui/input";
|
||||
import { PasswordInput } from "@/components/password-input";
|
||||
import { registerUser } from "@/lib/api";
|
||||
import { ApiError } from "@/errors/api-error";
|
||||
import useAuth from "@/hooks/useAuth";
|
||||
import { PhoneInput } from "@/components/ui/phone-number-input";
|
||||
|
||||
type SignUpFormProps = HTMLAttributes<HTMLDivElement>;
|
||||
|
||||
@ -64,6 +66,7 @@ const formSchema = z
|
||||
});
|
||||
|
||||
export function SignUpForm({ className, ...props }: SignUpFormProps) {
|
||||
const { signUpMutation } = useAuth();
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [successMessage, setSuccessMessage] = useState<string | null>(null);
|
||||
@ -85,12 +88,7 @@ export function SignUpForm({ className, ...props }: SignUpFormProps) {
|
||||
setSuccessMessage(null);
|
||||
|
||||
try {
|
||||
await registerUser({
|
||||
username: data.username,
|
||||
email: data.email,
|
||||
password: data.password,
|
||||
phone_number: data.phone_number
|
||||
});
|
||||
signUpMutation.mutate(data);
|
||||
setSuccessMessage("Account created successfully!");
|
||||
} catch (error: unknown) {
|
||||
setError(error instanceof ApiError ? error.response : "Something went wrong.");
|
||||
@ -137,7 +135,7 @@ export function SignUpForm({ className, ...props }: SignUpFormProps) {
|
||||
<FormItem className="space-y-1">
|
||||
<FormLabel>Phone Number</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="+1234567890" {...field} />
|
||||
<PhoneInput {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
@ -33,9 +32,6 @@ export default function Dashboard() {
|
||||
<Main>
|
||||
<div className="mb-2 flex items-center justify-between space-y-2">
|
||||
<h1 className="text-2xl font-bold tracking-tight">Dashboard</h1>
|
||||
<div className="flex items-center space-x-2">
|
||||
<Button>Download</Button>
|
||||
</div>
|
||||
</div>
|
||||
<Tabs
|
||||
orientation="vertical"
|
||||
|
@ -18,8 +18,6 @@ export default function MainPage() {
|
||||
<Pricing />
|
||||
<Faq />
|
||||
<CallToAction />
|
||||
|
||||
{/* [Optional] Consider inserting an image or illustration here to reinforce the platform’s purpose. */}
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
@ -1,3 +0,0 @@
|
||||
export default function Nba() {
|
||||
return <h1>NBA Testing</h1>;
|
||||
}
|
@ -27,7 +27,7 @@ const appText = new Map<string, string>([
|
||||
["notConnected", "Not Connected"]
|
||||
]);
|
||||
|
||||
export default function Apps() {
|
||||
export default function Products() {
|
||||
const [sort, setSort] = useState("ascending");
|
||||
const [appType, setAppType] = useState("all");
|
||||
const [searchTerm, setSearchTerm] = useState("");
|
@ -1,86 +1,63 @@
|
||||
import { z } from "zod";
|
||||
import { format } from "date-fns";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { CalendarIcon, CaretSortIcon, CheckIcon } from "@radix-ui/react-icons";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { toast } from "@/hooks/useToast";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Calendar } from "@/components/ui/calendar";
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList
|
||||
} from "@/components/ui/command";
|
||||
import {
|
||||
import
|
||||
{
|
||||
Form,
|
||||
FormControl,
|
||||
FormDescription,
|
||||
FormField,
|
||||
FormControl, FormField,
|
||||
FormItem,
|
||||
FormLabel,
|
||||
FormMessage
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger
|
||||
} from "@/components/ui/popover";
|
||||
import useAuth from "@/hooks/useAuth";
|
||||
|
||||
const languages = [
|
||||
{ label: "English", value: "en" },
|
||||
{ label: "French", value: "fr" },
|
||||
{ label: "German", value: "de" },
|
||||
{ label: "Spanish", value: "es" },
|
||||
{ label: "Portuguese", value: "pt" },
|
||||
{ label: "Russian", value: "ru" },
|
||||
{ label: "Japanese", value: "ja" },
|
||||
{ label: "Korean", value: "ko" },
|
||||
{ label: "Chinese", value: "zh" }
|
||||
] as const;
|
||||
// const languages = [
|
||||
// { label: "English", value: "en" },
|
||||
// { label: "French", value: "fr" },
|
||||
// { label: "German", value: "de" },
|
||||
// { label: "Spanish", value: "es" },
|
||||
// { label: "Portuguese", value: "pt" },
|
||||
// { label: "Russian", value: "ru" },
|
||||
// { label: "Japanese", value: "ja" },
|
||||
// { label: "Korean", value: "ko" },
|
||||
// { label: "Chinese", value: "zh" }
|
||||
// ] as const;
|
||||
|
||||
const accountFormSchema = z.object({
|
||||
name: z
|
||||
.string()
|
||||
.min(2, {
|
||||
message: "Name must be at least 2 characters."
|
||||
})
|
||||
.max(30, {
|
||||
message: "Name must not be longer than 30 characters."
|
||||
}),
|
||||
dob: z.date({
|
||||
required_error: "A date of birth is required."
|
||||
}),
|
||||
language: z.string({
|
||||
required_error: "Please select a language."
|
||||
})
|
||||
username: z.string().min(3).max(30),
|
||||
email: z.string().email(),
|
||||
phone_number: z.string(),
|
||||
// password: z.string().min(8).max(128),
|
||||
first_name: z.string().optional(),
|
||||
last_name: z.string().optional(),
|
||||
// dob: z.date({
|
||||
// required_error: "A date of birth is required."
|
||||
// }),
|
||||
// language: z.string({
|
||||
// required_error: "Please select a language."
|
||||
// })
|
||||
});
|
||||
|
||||
type AccountFormValues = z.infer<typeof accountFormSchema>;
|
||||
|
||||
// This can come from your database or API.
|
||||
const defaultValues: Partial<AccountFormValues> = {
|
||||
name: ""
|
||||
};
|
||||
|
||||
export function AccountForm() {
|
||||
const { updateAccountMutation, user } = useAuth();
|
||||
|
||||
const form = useForm<AccountFormValues>({
|
||||
resolver: zodResolver(accountFormSchema),
|
||||
defaultValues
|
||||
resolver: zodResolver(accountFormSchema)
|
||||
});
|
||||
|
||||
function onSubmit(data: AccountFormValues) {
|
||||
toast({
|
||||
title: "You submitted the following values:",
|
||||
description: (
|
||||
<pre className="mt-2 w-[340px] rounded-md bg-slate-950 p-4">
|
||||
<code className="text-white">{JSON.stringify(data, null, 2)}</code>
|
||||
</pre>
|
||||
)
|
||||
updateAccountMutation.mutate({
|
||||
email: data.email,
|
||||
// password: data.password,
|
||||
password: "null",
|
||||
phone_number: data.phone_number,
|
||||
username: data.username,
|
||||
first_name: data.first_name,
|
||||
last_name: data.last_name
|
||||
});
|
||||
}
|
||||
|
||||
@ -89,125 +66,57 @@ export function AccountForm() {
|
||||
<form onSubmit={form.handleSubmit(onSubmit)} className="space-y-8">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="name"
|
||||
name="username"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Name</FormLabel>
|
||||
<FormLabel>Username</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="Your name" {...field} />
|
||||
<Input placeholder="Your username" defaultValue={user?.username} {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
This is the name that will be displayed on your profile and in
|
||||
emails.
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="dob"
|
||||
name="email"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Date of birth</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormItem>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<FormControl>
|
||||
<Button
|
||||
variant={"outline"}
|
||||
className={cn(
|
||||
"w-[240px] pl-3 text-left font-normal",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}>
|
||||
{field.value ? (
|
||||
format(field.value, "MMM d, yyyy")
|
||||
) : (
|
||||
<span>Pick a date</span>
|
||||
)}
|
||||
<CalendarIcon className="ml-auto h-4 w-4 opacity-50" />
|
||||
</Button>
|
||||
<Input placeholder="Your email" defaultValue={user?.email} {...field} />
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-auto p-0" align="start">
|
||||
<Calendar
|
||||
mode="single"
|
||||
selected={field.value}
|
||||
onSelect={field.onChange}
|
||||
disabled={(date: Date) =>
|
||||
date > new Date() || date < new Date("1900-01-01")
|
||||
}
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormDescription>
|
||||
Your date of birth is used to calculate your age.
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="language"
|
||||
name="phone_number"
|
||||
render={({ field }) => (
|
||||
<FormItem className="flex flex-col">
|
||||
<FormLabel>Language</FormLabel>
|
||||
<Popover>
|
||||
<PopoverTrigger asChild>
|
||||
<FormItem>
|
||||
<FormLabel>Phone Number</FormLabel>
|
||||
<FormControl>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
className={cn(
|
||||
"w-[200px] justify-between",
|
||||
!field.value && "text-muted-foreground"
|
||||
)}>
|
||||
{field.value
|
||||
? languages.find(
|
||||
(language) => language.value === field.value
|
||||
)?.label
|
||||
: "Select language"}
|
||||
<CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
<Input placeholder="Your phone number" defaultValue={user?.phone_number} {...field} />
|
||||
</FormControl>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[200px] p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder="Search language..." />
|
||||
<CommandEmpty>No language found.</CommandEmpty>
|
||||
<CommandGroup>
|
||||
<CommandList>
|
||||
{languages.map((language) => (
|
||||
<CommandItem
|
||||
value={language.label}
|
||||
key={language.value}
|
||||
onSelect={() => {
|
||||
form.setValue("language", language.value);
|
||||
}}>
|
||||
<CheckIcon
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4",
|
||||
language.value === field.value
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
)}
|
||||
/>
|
||||
{language.label}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandList>
|
||||
</CommandGroup>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<FormDescription>
|
||||
This is the language that will be used in the dashboard.
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button type="submit">Update account</Button>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="password"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Password</FormLabel>
|
||||
<FormControl>
|
||||
<Input type="password" placeholder="New password" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<Button type="submit">Update Account</Button>
|
||||
</form>
|
||||
</Form>
|
||||
);
|
||||
|
@ -1,9 +1,9 @@
|
||||
import { Outlet } from "@tanstack/react-router";
|
||||
import {
|
||||
IconBrowserCheck,
|
||||
IconLock,
|
||||
IconNotification,
|
||||
IconPalette,
|
||||
IconTool,
|
||||
IconUser
|
||||
} from "@tabler/icons-react";
|
||||
import { Separator } from "@/components/ui/separator";
|
||||
@ -53,26 +53,26 @@ const sidebarNavItems = [
|
||||
{
|
||||
title: "Profile",
|
||||
icon: <IconUser size={18} />,
|
||||
href: "/settings"
|
||||
href: "/dashboard/settings"
|
||||
},
|
||||
{
|
||||
title: "Account",
|
||||
icon: <IconTool size={18} />,
|
||||
href: "/settings/account"
|
||||
title: "Security",
|
||||
icon: <IconLock size={18} />,
|
||||
href: "/dashboard/settings/security"
|
||||
},
|
||||
{
|
||||
title: "Appearance",
|
||||
icon: <IconPalette size={18} />,
|
||||
href: "/settings/appearance"
|
||||
href: "/dashboard/settings/appearance"
|
||||
},
|
||||
{
|
||||
title: "Notifications",
|
||||
icon: <IconNotification size={18} />,
|
||||
href: "/settings/notifications"
|
||||
href: "/dashboard/settings/notifications"
|
||||
},
|
||||
{
|
||||
title: "Display",
|
||||
icon: <IconBrowserCheck size={18} />,
|
||||
href: "/settings/display"
|
||||
href: "/dashboard/settings/display"
|
||||
}
|
||||
];
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { z } from "zod";
|
||||
import { useFieldArray, useForm } from "react-hook-form";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { Link } from "@tanstack/react-router";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { toast } from "@/hooks/useToast";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
@ -15,63 +14,71 @@ import {
|
||||
FormMessage
|
||||
} from "@/components/ui/form";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue
|
||||
} from "@/components/ui/select";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { PhoneInput } from "@/components/ui/phone-number-input";
|
||||
import useAuth from "@/hooks/useAuth";
|
||||
|
||||
const profileFormSchema = z.object({
|
||||
username: z
|
||||
.string()
|
||||
.min(2, {
|
||||
message: "Username must be at least 2 characters."
|
||||
.string({
|
||||
required_error: "Please enter your desired username"
|
||||
})
|
||||
.max(30, {
|
||||
message: "Username must not be longer than 30 characters."
|
||||
.min(3, {
|
||||
message: "Username must be at least 3 characters."
|
||||
})
|
||||
.max(64, {
|
||||
message: "Username must not be longer than 64 characters."
|
||||
}),
|
||||
email: z
|
||||
.string({
|
||||
required_error: "Please select an email to display."
|
||||
.string()
|
||||
.email({
|
||||
message: "Please enter your email address."
|
||||
})
|
||||
.email(),
|
||||
bio: z.string().max(160).min(4),
|
||||
urls: z
|
||||
.array(
|
||||
z.object({
|
||||
value: z.string().url({ message: "Please enter a valid URL." })
|
||||
phone_number: z
|
||||
.string({
|
||||
required_error: "Please input a valid phone number."
|
||||
})
|
||||
.min(2, {
|
||||
message: "Phone number must be at least 2 characters."
|
||||
})
|
||||
.max(16, {
|
||||
message: "Phone number must not be longer than 16 characters."
|
||||
}),
|
||||
first_name: z
|
||||
.string()
|
||||
.max(64, {
|
||||
message: "First name must not be longer than 64 characters."
|
||||
})
|
||||
.optional(),
|
||||
last_name: z
|
||||
.string()
|
||||
.max(64, {
|
||||
message: "Last name must not be longer than 64 characters."
|
||||
})
|
||||
)
|
||||
.optional()
|
||||
});
|
||||
|
||||
type ProfileFormValues = z.infer<typeof profileFormSchema>;
|
||||
|
||||
// This can come from your database or API.
|
||||
const defaultValues: Partial<ProfileFormValues> = {
|
||||
bio: "I own a computer.",
|
||||
urls: [
|
||||
{ value: "https://shadcn.com" },
|
||||
{ value: "http://twitter.com/shadcn" }
|
||||
]
|
||||
export default function ProfileForm() {
|
||||
const { user, updateAccountMutation } = useAuth();
|
||||
|
||||
const defaultValues: ProfileFormValues = {
|
||||
username: user?.username ?? "",
|
||||
email: user?.email ?? "",
|
||||
phone_number: user?.phone_number ?? "",
|
||||
first_name: user?.first_name ?? "",
|
||||
last_name: user?.last_name ?? ""
|
||||
};
|
||||
|
||||
export default function ProfileForm() {
|
||||
const form = useForm<ProfileFormValues>({
|
||||
resolver: zodResolver(profileFormSchema),
|
||||
defaultValues,
|
||||
mode: "onChange"
|
||||
});
|
||||
|
||||
const { fields, append } = useFieldArray({
|
||||
name: "urls",
|
||||
control: form.control
|
||||
});
|
||||
|
||||
function onSubmit(data: ProfileFormValues) {
|
||||
updateAccountMutation.mutate(data);
|
||||
toast({
|
||||
title: "You submitted the following values:",
|
||||
description: (
|
||||
@ -92,11 +99,11 @@ export default function ProfileForm() {
|
||||
<FormItem>
|
||||
<FormLabel>Username</FormLabel>
|
||||
<FormControl>
|
||||
<Input placeholder="shadcn" {...field} />
|
||||
<Input placeholder="Username" {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
This is your public display name. It can be your real name or a
|
||||
pseudonym. You can only change this once every 30 days.
|
||||
pseudonym.
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@ -108,18 +115,9 @@ export default function ProfileForm() {
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Email</FormLabel>
|
||||
<Select onValueChange={field.onChange} defaultValue={field.value}>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue placeholder="Select a verified email to display" />
|
||||
</SelectTrigger>
|
||||
<Input type="email" {...field} />
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="m@example.com">m@example.com</SelectItem>
|
||||
<SelectItem value="m@google.com">m@google.com</SelectItem>
|
||||
<SelectItem value="m@support.com">m@support.com</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormDescription>
|
||||
You can manage verified email addresses in your{" "}
|
||||
<Link to="/">email settings</Link>.
|
||||
@ -130,56 +128,44 @@ export default function ProfileForm() {
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="bio"
|
||||
name="first_name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Bio</FormLabel>
|
||||
<FormLabel>First Name</FormLabel>
|
||||
<FormControl>
|
||||
<Textarea
|
||||
placeholder="Tell us a little bit about yourself"
|
||||
className="resize-none"
|
||||
{...field}
|
||||
/>
|
||||
<Input placeholder="John" {...field} />
|
||||
</FormControl>
|
||||
<FormDescription>
|
||||
You can <span>@mention</span> other users and organizations to
|
||||
link to them.
|
||||
</FormDescription>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<div>
|
||||
{fields.map((field, index) => (
|
||||
<FormField
|
||||
control={form.control}
|
||||
key={field.id}
|
||||
name={`urls.${index}.value`}
|
||||
name="last_name"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel className={cn(index !== 0 && "sr-only")}>
|
||||
URLs
|
||||
</FormLabel>
|
||||
<FormDescription className={cn(index !== 0 && "sr-only")}>
|
||||
Add links to your website, blog, or social media profiles.
|
||||
</FormDescription>
|
||||
<FormLabel>Last Name</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
<Input placeholder="Doe" {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="phone_number"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>Phone number</FormLabel>
|
||||
<FormControl>
|
||||
<PhoneInput {...field} />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
className="mt-2"
|
||||
onClick={() => append({ value: "" })}>
|
||||
Add URL
|
||||
</Button>
|
||||
</div>
|
||||
<Button type="submit">Update profile</Button>
|
||||
</form>
|
||||
</Form>
|
||||
|
0
frontend/src/pages/settings/security/index.tsx
Normal file
0
frontend/src/pages/settings/security/index.tsx
Normal file
@ -32,41 +32,47 @@ const authSignIn2LazyImport = createFileRoute('/(auth)/sign-in-2')()
|
||||
const authForgotPasswordLazyImport = createFileRoute(
|
||||
'/(auth)/forgot-password',
|
||||
)()
|
||||
const AuthenticatedSettingsRouteLazyImport = createFileRoute(
|
||||
'/_authenticated/settings',
|
||||
)()
|
||||
const AuthenticatedUsersIndexLazyImport = createFileRoute(
|
||||
'/_authenticated/users/',
|
||||
)()
|
||||
const AuthenticatedTasksIndexLazyImport = createFileRoute(
|
||||
'/_authenticated/tasks/',
|
||||
)()
|
||||
const AuthenticatedSettingsIndexLazyImport = createFileRoute(
|
||||
'/_authenticated/settings/',
|
||||
)()
|
||||
const AuthenticatedNbaIndexLazyImport = createFileRoute(
|
||||
'/_authenticated/nba/',
|
||||
)()
|
||||
const AuthenticatedHelpCenterIndexLazyImport = createFileRoute(
|
||||
'/_authenticated/help-center/',
|
||||
)()
|
||||
const AuthenticatedChatsIndexLazyImport = createFileRoute(
|
||||
'/_authenticated/chats/',
|
||||
const AuthenticatedDashboardSettingsRouteLazyImport = createFileRoute(
|
||||
'/_authenticated/dashboard/settings',
|
||||
)()
|
||||
const AuthenticatedAppsIndexLazyImport = createFileRoute(
|
||||
'/_authenticated/apps/',
|
||||
const AuthenticatedDashboardUsersIndexLazyImport = createFileRoute(
|
||||
'/_authenticated/dashboard/users/',
|
||||
)()
|
||||
const AuthenticatedSettingsNotificationsLazyImport = createFileRoute(
|
||||
'/_authenticated/settings/notifications',
|
||||
const AuthenticatedDashboardTasksIndexLazyImport = createFileRoute(
|
||||
'/_authenticated/dashboard/tasks/',
|
||||
)()
|
||||
const AuthenticatedSettingsDisplayLazyImport = createFileRoute(
|
||||
'/_authenticated/settings/display',
|
||||
const AuthenticatedDashboardSettingsIndexLazyImport = createFileRoute(
|
||||
'/_authenticated/dashboard/settings/',
|
||||
)()
|
||||
const AuthenticatedSettingsAppearanceLazyImport = createFileRoute(
|
||||
'/_authenticated/settings/appearance',
|
||||
const AuthenticatedDashboardSalesIndexLazyImport = createFileRoute(
|
||||
'/_authenticated/dashboard/sales/',
|
||||
)()
|
||||
const AuthenticatedSettingsAccountLazyImport = createFileRoute(
|
||||
'/_authenticated/settings/account',
|
||||
const AuthenticatedDashboardProductsIndexLazyImport = createFileRoute(
|
||||
'/_authenticated/dashboard/products/',
|
||||
)()
|
||||
const AuthenticatedDashboardChatsIndexLazyImport = createFileRoute(
|
||||
'/_authenticated/dashboard/chats/',
|
||||
)()
|
||||
const AuthenticatedDashboardSettingsNotificationsLazyImport = createFileRoute(
|
||||
'/_authenticated/dashboard/settings/notifications',
|
||||
)()
|
||||
const AuthenticatedDashboardSettingsDisplayLazyImport = createFileRoute(
|
||||
'/_authenticated/dashboard/settings/display',
|
||||
)()
|
||||
const AuthenticatedDashboardSettingsAppearanceLazyImport = createFileRoute(
|
||||
'/_authenticated/dashboard/settings/appearance',
|
||||
)()
|
||||
const AuthenticatedDashboardSettingsAccountLazyImport = createFileRoute(
|
||||
'/_authenticated/dashboard/settings/account',
|
||||
)()
|
||||
const AuthenticatedDashboardSalesDiscountsLazyImport = createFileRoute(
|
||||
'/_authenticated/dashboard/sales/discounts',
|
||||
)()
|
||||
const AuthenticatedDashboardSalesCouponsLazyImport = createFileRoute(
|
||||
'/_authenticated/dashboard/sales/coupons',
|
||||
)()
|
||||
|
||||
// Create/Update Routes
|
||||
@ -148,15 +154,6 @@ const authForgotPasswordLazyRoute = authForgotPasswordLazyImport
|
||||
import('./routes/(auth)/forgot-password.lazy').then((d) => d.Route),
|
||||
)
|
||||
|
||||
const AuthenticatedSettingsRouteLazyRoute =
|
||||
AuthenticatedSettingsRouteLazyImport.update({
|
||||
id: '/settings',
|
||||
path: '/settings',
|
||||
getParentRoute: () => AuthenticatedRouteRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/settings/route.lazy').then((d) => d.Route),
|
||||
)
|
||||
|
||||
const authSignInRoute = authSignInImport.update({
|
||||
id: '/(auth)/sign-in',
|
||||
path: '/sign-in',
|
||||
@ -175,41 +172,6 @@ const auth500Route = auth500Import.update({
|
||||
getParentRoute: () => rootRoute,
|
||||
} as any)
|
||||
|
||||
const AuthenticatedUsersIndexLazyRoute =
|
||||
AuthenticatedUsersIndexLazyImport.update({
|
||||
id: '/users/',
|
||||
path: '/users/',
|
||||
getParentRoute: () => AuthenticatedRouteRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/users/index.lazy').then((d) => d.Route),
|
||||
)
|
||||
|
||||
const AuthenticatedTasksIndexLazyRoute =
|
||||
AuthenticatedTasksIndexLazyImport.update({
|
||||
id: '/tasks/',
|
||||
path: '/tasks/',
|
||||
getParentRoute: () => AuthenticatedRouteRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/tasks/index.lazy').then((d) => d.Route),
|
||||
)
|
||||
|
||||
const AuthenticatedSettingsIndexLazyRoute =
|
||||
AuthenticatedSettingsIndexLazyImport.update({
|
||||
id: '/',
|
||||
path: '/',
|
||||
getParentRoute: () => AuthenticatedSettingsRouteLazyRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/settings/index.lazy').then((d) => d.Route),
|
||||
)
|
||||
|
||||
const AuthenticatedNbaIndexLazyRoute = AuthenticatedNbaIndexLazyImport.update({
|
||||
id: '/nba/',
|
||||
path: '/nba/',
|
||||
getParentRoute: () => AuthenticatedRouteRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/nba/index.lazy').then((d) => d.Route),
|
||||
)
|
||||
|
||||
const AuthenticatedHelpCenterIndexLazyRoute =
|
||||
AuthenticatedHelpCenterIndexLazyImport.update({
|
||||
id: '/help-center/',
|
||||
@ -221,25 +183,6 @@ const AuthenticatedHelpCenterIndexLazyRoute =
|
||||
),
|
||||
)
|
||||
|
||||
const AuthenticatedChatsIndexLazyRoute =
|
||||
AuthenticatedChatsIndexLazyImport.update({
|
||||
id: '/chats/',
|
||||
path: '/chats/',
|
||||
getParentRoute: () => AuthenticatedRouteRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/chats/index.lazy').then((d) => d.Route),
|
||||
)
|
||||
|
||||
const AuthenticatedAppsIndexLazyRoute = AuthenticatedAppsIndexLazyImport.update(
|
||||
{
|
||||
id: '/apps/',
|
||||
path: '/apps/',
|
||||
getParentRoute: () => AuthenticatedRouteRoute,
|
||||
} as any,
|
||||
).lazy(() =>
|
||||
import('./routes/_authenticated/apps/index.lazy').then((d) => d.Route),
|
||||
)
|
||||
|
||||
const AuthenticatedDashboardIndexRoute =
|
||||
AuthenticatedDashboardIndexImport.update({
|
||||
id: '/dashboard/',
|
||||
@ -247,46 +190,145 @@ const AuthenticatedDashboardIndexRoute =
|
||||
getParentRoute: () => AuthenticatedRouteRoute,
|
||||
} as any)
|
||||
|
||||
const AuthenticatedSettingsNotificationsLazyRoute =
|
||||
AuthenticatedSettingsNotificationsLazyImport.update({
|
||||
const AuthenticatedDashboardSettingsRouteLazyRoute =
|
||||
AuthenticatedDashboardSettingsRouteLazyImport.update({
|
||||
id: '/dashboard/settings',
|
||||
path: '/dashboard/settings',
|
||||
getParentRoute: () => AuthenticatedRouteRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/dashboard/settings/route.lazy').then(
|
||||
(d) => d.Route,
|
||||
),
|
||||
)
|
||||
|
||||
const AuthenticatedDashboardUsersIndexLazyRoute =
|
||||
AuthenticatedDashboardUsersIndexLazyImport.update({
|
||||
id: '/dashboard/users/',
|
||||
path: '/dashboard/users/',
|
||||
getParentRoute: () => AuthenticatedRouteRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/dashboard/users/index.lazy').then(
|
||||
(d) => d.Route,
|
||||
),
|
||||
)
|
||||
|
||||
const AuthenticatedDashboardTasksIndexLazyRoute =
|
||||
AuthenticatedDashboardTasksIndexLazyImport.update({
|
||||
id: '/dashboard/tasks/',
|
||||
path: '/dashboard/tasks/',
|
||||
getParentRoute: () => AuthenticatedRouteRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/dashboard/tasks/index.lazy').then(
|
||||
(d) => d.Route,
|
||||
),
|
||||
)
|
||||
|
||||
const AuthenticatedDashboardSettingsIndexLazyRoute =
|
||||
AuthenticatedDashboardSettingsIndexLazyImport.update({
|
||||
id: '/',
|
||||
path: '/',
|
||||
getParentRoute: () => AuthenticatedDashboardSettingsRouteLazyRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/dashboard/settings/index.lazy').then(
|
||||
(d) => d.Route,
|
||||
),
|
||||
)
|
||||
|
||||
const AuthenticatedDashboardSalesIndexLazyRoute =
|
||||
AuthenticatedDashboardSalesIndexLazyImport.update({
|
||||
id: '/dashboard/sales/',
|
||||
path: '/dashboard/sales/',
|
||||
getParentRoute: () => AuthenticatedRouteRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/dashboard/sales/index.lazy').then(
|
||||
(d) => d.Route,
|
||||
),
|
||||
)
|
||||
|
||||
const AuthenticatedDashboardProductsIndexLazyRoute =
|
||||
AuthenticatedDashboardProductsIndexLazyImport.update({
|
||||
id: '/dashboard/products/',
|
||||
path: '/dashboard/products/',
|
||||
getParentRoute: () => AuthenticatedRouteRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/dashboard/products/index.lazy').then(
|
||||
(d) => d.Route,
|
||||
),
|
||||
)
|
||||
|
||||
const AuthenticatedDashboardChatsIndexLazyRoute =
|
||||
AuthenticatedDashboardChatsIndexLazyImport.update({
|
||||
id: '/dashboard/chats/',
|
||||
path: '/dashboard/chats/',
|
||||
getParentRoute: () => AuthenticatedRouteRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/dashboard/chats/index.lazy').then(
|
||||
(d) => d.Route,
|
||||
),
|
||||
)
|
||||
|
||||
const AuthenticatedDashboardSettingsNotificationsLazyRoute =
|
||||
AuthenticatedDashboardSettingsNotificationsLazyImport.update({
|
||||
id: '/notifications',
|
||||
path: '/notifications',
|
||||
getParentRoute: () => AuthenticatedSettingsRouteLazyRoute,
|
||||
getParentRoute: () => AuthenticatedDashboardSettingsRouteLazyRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/settings/notifications.lazy').then(
|
||||
(d) => d.Route,
|
||||
),
|
||||
import(
|
||||
'./routes/_authenticated/dashboard/settings/notifications.lazy'
|
||||
).then((d) => d.Route),
|
||||
)
|
||||
|
||||
const AuthenticatedSettingsDisplayLazyRoute =
|
||||
AuthenticatedSettingsDisplayLazyImport.update({
|
||||
const AuthenticatedDashboardSettingsDisplayLazyRoute =
|
||||
AuthenticatedDashboardSettingsDisplayLazyImport.update({
|
||||
id: '/display',
|
||||
path: '/display',
|
||||
getParentRoute: () => AuthenticatedSettingsRouteLazyRoute,
|
||||
getParentRoute: () => AuthenticatedDashboardSettingsRouteLazyRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/settings/display.lazy').then(
|
||||
import('./routes/_authenticated/dashboard/settings/display.lazy').then(
|
||||
(d) => d.Route,
|
||||
),
|
||||
)
|
||||
|
||||
const AuthenticatedSettingsAppearanceLazyRoute =
|
||||
AuthenticatedSettingsAppearanceLazyImport.update({
|
||||
const AuthenticatedDashboardSettingsAppearanceLazyRoute =
|
||||
AuthenticatedDashboardSettingsAppearanceLazyImport.update({
|
||||
id: '/appearance',
|
||||
path: '/appearance',
|
||||
getParentRoute: () => AuthenticatedSettingsRouteLazyRoute,
|
||||
getParentRoute: () => AuthenticatedDashboardSettingsRouteLazyRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/settings/appearance.lazy').then(
|
||||
import('./routes/_authenticated/dashboard/settings/appearance.lazy').then(
|
||||
(d) => d.Route,
|
||||
),
|
||||
)
|
||||
|
||||
const AuthenticatedSettingsAccountLazyRoute =
|
||||
AuthenticatedSettingsAccountLazyImport.update({
|
||||
const AuthenticatedDashboardSettingsAccountLazyRoute =
|
||||
AuthenticatedDashboardSettingsAccountLazyImport.update({
|
||||
id: '/account',
|
||||
path: '/account',
|
||||
getParentRoute: () => AuthenticatedSettingsRouteLazyRoute,
|
||||
getParentRoute: () => AuthenticatedDashboardSettingsRouteLazyRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/settings/account.lazy').then(
|
||||
import('./routes/_authenticated/dashboard/settings/account.lazy').then(
|
||||
(d) => d.Route,
|
||||
),
|
||||
)
|
||||
|
||||
const AuthenticatedDashboardSalesDiscountsLazyRoute =
|
||||
AuthenticatedDashboardSalesDiscountsLazyImport.update({
|
||||
id: '/dashboard/sales/discounts',
|
||||
path: '/dashboard/sales/discounts',
|
||||
getParentRoute: () => AuthenticatedRouteRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/dashboard/sales/discounts.lazy').then(
|
||||
(d) => d.Route,
|
||||
),
|
||||
)
|
||||
|
||||
const AuthenticatedDashboardSalesCouponsLazyRoute =
|
||||
AuthenticatedDashboardSalesCouponsLazyImport.update({
|
||||
id: '/dashboard/sales/coupons',
|
||||
path: '/dashboard/sales/coupons',
|
||||
getParentRoute: () => AuthenticatedRouteRoute,
|
||||
} as any).lazy(() =>
|
||||
import('./routes/_authenticated/dashboard/sales/coupons.lazy').then(
|
||||
(d) => d.Route,
|
||||
),
|
||||
)
|
||||
@ -330,13 +372,6 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof authSignInImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/_authenticated/settings': {
|
||||
id: '/_authenticated/settings'
|
||||
path: '/settings'
|
||||
fullPath: '/settings'
|
||||
preLoaderRoute: typeof AuthenticatedSettingsRouteLazyImport
|
||||
parentRoute: typeof AuthenticatedRouteImport
|
||||
}
|
||||
'/(auth)/forgot-password': {
|
||||
id: '/(auth)/forgot-password'
|
||||
path: '/forgot-password'
|
||||
@ -393,33 +428,12 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof errors503LazyImport
|
||||
parentRoute: typeof rootRoute
|
||||
}
|
||||
'/_authenticated/settings/account': {
|
||||
id: '/_authenticated/settings/account'
|
||||
path: '/account'
|
||||
fullPath: '/settings/account'
|
||||
preLoaderRoute: typeof AuthenticatedSettingsAccountLazyImport
|
||||
parentRoute: typeof AuthenticatedSettingsRouteLazyImport
|
||||
}
|
||||
'/_authenticated/settings/appearance': {
|
||||
id: '/_authenticated/settings/appearance'
|
||||
path: '/appearance'
|
||||
fullPath: '/settings/appearance'
|
||||
preLoaderRoute: typeof AuthenticatedSettingsAppearanceLazyImport
|
||||
parentRoute: typeof AuthenticatedSettingsRouteLazyImport
|
||||
}
|
||||
'/_authenticated/settings/display': {
|
||||
id: '/_authenticated/settings/display'
|
||||
path: '/display'
|
||||
fullPath: '/settings/display'
|
||||
preLoaderRoute: typeof AuthenticatedSettingsDisplayLazyImport
|
||||
parentRoute: typeof AuthenticatedSettingsRouteLazyImport
|
||||
}
|
||||
'/_authenticated/settings/notifications': {
|
||||
id: '/_authenticated/settings/notifications'
|
||||
path: '/notifications'
|
||||
fullPath: '/settings/notifications'
|
||||
preLoaderRoute: typeof AuthenticatedSettingsNotificationsLazyImport
|
||||
parentRoute: typeof AuthenticatedSettingsRouteLazyImport
|
||||
'/_authenticated/dashboard/settings': {
|
||||
id: '/_authenticated/dashboard/settings'
|
||||
path: '/dashboard/settings'
|
||||
fullPath: '/dashboard/settings'
|
||||
preLoaderRoute: typeof AuthenticatedDashboardSettingsRouteLazyImport
|
||||
parentRoute: typeof AuthenticatedRouteImport
|
||||
}
|
||||
'/_authenticated/dashboard/': {
|
||||
id: '/_authenticated/dashboard/'
|
||||
@ -428,20 +442,6 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof AuthenticatedDashboardIndexImport
|
||||
parentRoute: typeof AuthenticatedRouteImport
|
||||
}
|
||||
'/_authenticated/apps/': {
|
||||
id: '/_authenticated/apps/'
|
||||
path: '/apps'
|
||||
fullPath: '/apps'
|
||||
preLoaderRoute: typeof AuthenticatedAppsIndexLazyImport
|
||||
parentRoute: typeof AuthenticatedRouteImport
|
||||
}
|
||||
'/_authenticated/chats/': {
|
||||
id: '/_authenticated/chats/'
|
||||
path: '/chats'
|
||||
fullPath: '/chats'
|
||||
preLoaderRoute: typeof AuthenticatedChatsIndexLazyImport
|
||||
parentRoute: typeof AuthenticatedRouteImport
|
||||
}
|
||||
'/_authenticated/help-center/': {
|
||||
id: '/_authenticated/help-center/'
|
||||
path: '/help-center'
|
||||
@ -449,32 +449,88 @@ declare module '@tanstack/react-router' {
|
||||
preLoaderRoute: typeof AuthenticatedHelpCenterIndexLazyImport
|
||||
parentRoute: typeof AuthenticatedRouteImport
|
||||
}
|
||||
'/_authenticated/nba/': {
|
||||
id: '/_authenticated/nba/'
|
||||
path: '/nba'
|
||||
fullPath: '/nba'
|
||||
preLoaderRoute: typeof AuthenticatedNbaIndexLazyImport
|
||||
'/_authenticated/dashboard/sales/coupons': {
|
||||
id: '/_authenticated/dashboard/sales/coupons'
|
||||
path: '/dashboard/sales/coupons'
|
||||
fullPath: '/dashboard/sales/coupons'
|
||||
preLoaderRoute: typeof AuthenticatedDashboardSalesCouponsLazyImport
|
||||
parentRoute: typeof AuthenticatedRouteImport
|
||||
}
|
||||
'/_authenticated/settings/': {
|
||||
id: '/_authenticated/settings/'
|
||||
'/_authenticated/dashboard/sales/discounts': {
|
||||
id: '/_authenticated/dashboard/sales/discounts'
|
||||
path: '/dashboard/sales/discounts'
|
||||
fullPath: '/dashboard/sales/discounts'
|
||||
preLoaderRoute: typeof AuthenticatedDashboardSalesDiscountsLazyImport
|
||||
parentRoute: typeof AuthenticatedRouteImport
|
||||
}
|
||||
'/_authenticated/dashboard/settings/account': {
|
||||
id: '/_authenticated/dashboard/settings/account'
|
||||
path: '/account'
|
||||
fullPath: '/dashboard/settings/account'
|
||||
preLoaderRoute: typeof AuthenticatedDashboardSettingsAccountLazyImport
|
||||
parentRoute: typeof AuthenticatedDashboardSettingsRouteLazyImport
|
||||
}
|
||||
'/_authenticated/dashboard/settings/appearance': {
|
||||
id: '/_authenticated/dashboard/settings/appearance'
|
||||
path: '/appearance'
|
||||
fullPath: '/dashboard/settings/appearance'
|
||||
preLoaderRoute: typeof AuthenticatedDashboardSettingsAppearanceLazyImport
|
||||
parentRoute: typeof AuthenticatedDashboardSettingsRouteLazyImport
|
||||
}
|
||||
'/_authenticated/dashboard/settings/display': {
|
||||
id: '/_authenticated/dashboard/settings/display'
|
||||
path: '/display'
|
||||
fullPath: '/dashboard/settings/display'
|
||||
preLoaderRoute: typeof AuthenticatedDashboardSettingsDisplayLazyImport
|
||||
parentRoute: typeof AuthenticatedDashboardSettingsRouteLazyImport
|
||||
}
|
||||
'/_authenticated/dashboard/settings/notifications': {
|
||||
id: '/_authenticated/dashboard/settings/notifications'
|
||||
path: '/notifications'
|
||||
fullPath: '/dashboard/settings/notifications'
|
||||
preLoaderRoute: typeof AuthenticatedDashboardSettingsNotificationsLazyImport
|
||||
parentRoute: typeof AuthenticatedDashboardSettingsRouteLazyImport
|
||||
}
|
||||
'/_authenticated/dashboard/chats/': {
|
||||
id: '/_authenticated/dashboard/chats/'
|
||||
path: '/dashboard/chats'
|
||||
fullPath: '/dashboard/chats'
|
||||
preLoaderRoute: typeof AuthenticatedDashboardChatsIndexLazyImport
|
||||
parentRoute: typeof AuthenticatedRouteImport
|
||||
}
|
||||
'/_authenticated/dashboard/products/': {
|
||||
id: '/_authenticated/dashboard/products/'
|
||||
path: '/dashboard/products'
|
||||
fullPath: '/dashboard/products'
|
||||
preLoaderRoute: typeof AuthenticatedDashboardProductsIndexLazyImport
|
||||
parentRoute: typeof AuthenticatedRouteImport
|
||||
}
|
||||
'/_authenticated/dashboard/sales/': {
|
||||
id: '/_authenticated/dashboard/sales/'
|
||||
path: '/dashboard/sales'
|
||||
fullPath: '/dashboard/sales'
|
||||
preLoaderRoute: typeof AuthenticatedDashboardSalesIndexLazyImport
|
||||
parentRoute: typeof AuthenticatedRouteImport
|
||||
}
|
||||
'/_authenticated/dashboard/settings/': {
|
||||
id: '/_authenticated/dashboard/settings/'
|
||||
path: '/'
|
||||
fullPath: '/settings/'
|
||||
preLoaderRoute: typeof AuthenticatedSettingsIndexLazyImport
|
||||
parentRoute: typeof AuthenticatedSettingsRouteLazyImport
|
||||
fullPath: '/dashboard/settings/'
|
||||
preLoaderRoute: typeof AuthenticatedDashboardSettingsIndexLazyImport
|
||||
parentRoute: typeof AuthenticatedDashboardSettingsRouteLazyImport
|
||||
}
|
||||
'/_authenticated/tasks/': {
|
||||
id: '/_authenticated/tasks/'
|
||||
path: '/tasks'
|
||||
fullPath: '/tasks'
|
||||
preLoaderRoute: typeof AuthenticatedTasksIndexLazyImport
|
||||
'/_authenticated/dashboard/tasks/': {
|
||||
id: '/_authenticated/dashboard/tasks/'
|
||||
path: '/dashboard/tasks'
|
||||
fullPath: '/dashboard/tasks'
|
||||
preLoaderRoute: typeof AuthenticatedDashboardTasksIndexLazyImport
|
||||
parentRoute: typeof AuthenticatedRouteImport
|
||||
}
|
||||
'/_authenticated/users/': {
|
||||
id: '/_authenticated/users/'
|
||||
path: '/users'
|
||||
fullPath: '/users'
|
||||
preLoaderRoute: typeof AuthenticatedUsersIndexLazyImport
|
||||
'/_authenticated/dashboard/users/': {
|
||||
id: '/_authenticated/dashboard/users/'
|
||||
path: '/dashboard/users'
|
||||
fullPath: '/dashboard/users'
|
||||
preLoaderRoute: typeof AuthenticatedDashboardUsersIndexLazyImport
|
||||
parentRoute: typeof AuthenticatedRouteImport
|
||||
}
|
||||
}
|
||||
@ -482,53 +538,65 @@ declare module '@tanstack/react-router' {
|
||||
|
||||
// Create and export the route tree
|
||||
|
||||
interface AuthenticatedSettingsRouteLazyRouteChildren {
|
||||
AuthenticatedSettingsAccountLazyRoute: typeof AuthenticatedSettingsAccountLazyRoute
|
||||
AuthenticatedSettingsAppearanceLazyRoute: typeof AuthenticatedSettingsAppearanceLazyRoute
|
||||
AuthenticatedSettingsDisplayLazyRoute: typeof AuthenticatedSettingsDisplayLazyRoute
|
||||
AuthenticatedSettingsNotificationsLazyRoute: typeof AuthenticatedSettingsNotificationsLazyRoute
|
||||
AuthenticatedSettingsIndexLazyRoute: typeof AuthenticatedSettingsIndexLazyRoute
|
||||
interface AuthenticatedDashboardSettingsRouteLazyRouteChildren {
|
||||
AuthenticatedDashboardSettingsAccountLazyRoute: typeof AuthenticatedDashboardSettingsAccountLazyRoute
|
||||
AuthenticatedDashboardSettingsAppearanceLazyRoute: typeof AuthenticatedDashboardSettingsAppearanceLazyRoute
|
||||
AuthenticatedDashboardSettingsDisplayLazyRoute: typeof AuthenticatedDashboardSettingsDisplayLazyRoute
|
||||
AuthenticatedDashboardSettingsNotificationsLazyRoute: typeof AuthenticatedDashboardSettingsNotificationsLazyRoute
|
||||
AuthenticatedDashboardSettingsIndexLazyRoute: typeof AuthenticatedDashboardSettingsIndexLazyRoute
|
||||
}
|
||||
|
||||
const AuthenticatedSettingsRouteLazyRouteChildren: AuthenticatedSettingsRouteLazyRouteChildren =
|
||||
const AuthenticatedDashboardSettingsRouteLazyRouteChildren: AuthenticatedDashboardSettingsRouteLazyRouteChildren =
|
||||
{
|
||||
AuthenticatedSettingsAccountLazyRoute:
|
||||
AuthenticatedSettingsAccountLazyRoute,
|
||||
AuthenticatedSettingsAppearanceLazyRoute:
|
||||
AuthenticatedSettingsAppearanceLazyRoute,
|
||||
AuthenticatedSettingsDisplayLazyRoute:
|
||||
AuthenticatedSettingsDisplayLazyRoute,
|
||||
AuthenticatedSettingsNotificationsLazyRoute:
|
||||
AuthenticatedSettingsNotificationsLazyRoute,
|
||||
AuthenticatedSettingsIndexLazyRoute: AuthenticatedSettingsIndexLazyRoute,
|
||||
AuthenticatedDashboardSettingsAccountLazyRoute:
|
||||
AuthenticatedDashboardSettingsAccountLazyRoute,
|
||||
AuthenticatedDashboardSettingsAppearanceLazyRoute:
|
||||
AuthenticatedDashboardSettingsAppearanceLazyRoute,
|
||||
AuthenticatedDashboardSettingsDisplayLazyRoute:
|
||||
AuthenticatedDashboardSettingsDisplayLazyRoute,
|
||||
AuthenticatedDashboardSettingsNotificationsLazyRoute:
|
||||
AuthenticatedDashboardSettingsNotificationsLazyRoute,
|
||||
AuthenticatedDashboardSettingsIndexLazyRoute:
|
||||
AuthenticatedDashboardSettingsIndexLazyRoute,
|
||||
}
|
||||
|
||||
const AuthenticatedSettingsRouteLazyRouteWithChildren =
|
||||
AuthenticatedSettingsRouteLazyRoute._addFileChildren(
|
||||
AuthenticatedSettingsRouteLazyRouteChildren,
|
||||
const AuthenticatedDashboardSettingsRouteLazyRouteWithChildren =
|
||||
AuthenticatedDashboardSettingsRouteLazyRoute._addFileChildren(
|
||||
AuthenticatedDashboardSettingsRouteLazyRouteChildren,
|
||||
)
|
||||
|
||||
interface AuthenticatedRouteRouteChildren {
|
||||
AuthenticatedSettingsRouteLazyRoute: typeof AuthenticatedSettingsRouteLazyRouteWithChildren
|
||||
AuthenticatedDashboardSettingsRouteLazyRoute: typeof AuthenticatedDashboardSettingsRouteLazyRouteWithChildren
|
||||
AuthenticatedDashboardIndexRoute: typeof AuthenticatedDashboardIndexRoute
|
||||
AuthenticatedAppsIndexLazyRoute: typeof AuthenticatedAppsIndexLazyRoute
|
||||
AuthenticatedChatsIndexLazyRoute: typeof AuthenticatedChatsIndexLazyRoute
|
||||
AuthenticatedHelpCenterIndexLazyRoute: typeof AuthenticatedHelpCenterIndexLazyRoute
|
||||
AuthenticatedNbaIndexLazyRoute: typeof AuthenticatedNbaIndexLazyRoute
|
||||
AuthenticatedTasksIndexLazyRoute: typeof AuthenticatedTasksIndexLazyRoute
|
||||
AuthenticatedUsersIndexLazyRoute: typeof AuthenticatedUsersIndexLazyRoute
|
||||
AuthenticatedDashboardSalesCouponsLazyRoute: typeof AuthenticatedDashboardSalesCouponsLazyRoute
|
||||
AuthenticatedDashboardSalesDiscountsLazyRoute: typeof AuthenticatedDashboardSalesDiscountsLazyRoute
|
||||
AuthenticatedDashboardChatsIndexLazyRoute: typeof AuthenticatedDashboardChatsIndexLazyRoute
|
||||
AuthenticatedDashboardProductsIndexLazyRoute: typeof AuthenticatedDashboardProductsIndexLazyRoute
|
||||
AuthenticatedDashboardSalesIndexLazyRoute: typeof AuthenticatedDashboardSalesIndexLazyRoute
|
||||
AuthenticatedDashboardTasksIndexLazyRoute: typeof AuthenticatedDashboardTasksIndexLazyRoute
|
||||
AuthenticatedDashboardUsersIndexLazyRoute: typeof AuthenticatedDashboardUsersIndexLazyRoute
|
||||
}
|
||||
|
||||
const AuthenticatedRouteRouteChildren: AuthenticatedRouteRouteChildren = {
|
||||
AuthenticatedSettingsRouteLazyRoute:
|
||||
AuthenticatedSettingsRouteLazyRouteWithChildren,
|
||||
AuthenticatedDashboardSettingsRouteLazyRoute:
|
||||
AuthenticatedDashboardSettingsRouteLazyRouteWithChildren,
|
||||
AuthenticatedDashboardIndexRoute: AuthenticatedDashboardIndexRoute,
|
||||
AuthenticatedAppsIndexLazyRoute: AuthenticatedAppsIndexLazyRoute,
|
||||
AuthenticatedChatsIndexLazyRoute: AuthenticatedChatsIndexLazyRoute,
|
||||
AuthenticatedHelpCenterIndexLazyRoute: AuthenticatedHelpCenterIndexLazyRoute,
|
||||
AuthenticatedNbaIndexLazyRoute: AuthenticatedNbaIndexLazyRoute,
|
||||
AuthenticatedTasksIndexLazyRoute: AuthenticatedTasksIndexLazyRoute,
|
||||
AuthenticatedUsersIndexLazyRoute: AuthenticatedUsersIndexLazyRoute,
|
||||
AuthenticatedDashboardSalesCouponsLazyRoute:
|
||||
AuthenticatedDashboardSalesCouponsLazyRoute,
|
||||
AuthenticatedDashboardSalesDiscountsLazyRoute:
|
||||
AuthenticatedDashboardSalesDiscountsLazyRoute,
|
||||
AuthenticatedDashboardChatsIndexLazyRoute:
|
||||
AuthenticatedDashboardChatsIndexLazyRoute,
|
||||
AuthenticatedDashboardProductsIndexLazyRoute:
|
||||
AuthenticatedDashboardProductsIndexLazyRoute,
|
||||
AuthenticatedDashboardSalesIndexLazyRoute:
|
||||
AuthenticatedDashboardSalesIndexLazyRoute,
|
||||
AuthenticatedDashboardTasksIndexLazyRoute:
|
||||
AuthenticatedDashboardTasksIndexLazyRoute,
|
||||
AuthenticatedDashboardUsersIndexLazyRoute:
|
||||
AuthenticatedDashboardUsersIndexLazyRoute,
|
||||
}
|
||||
|
||||
const AuthenticatedRouteRouteWithChildren =
|
||||
@ -540,7 +608,6 @@ export interface FileRoutesByFullPath {
|
||||
'/500': typeof errors500LazyRoute
|
||||
'/otp': typeof authOtpRoute
|
||||
'/sign-in': typeof authSignInRoute
|
||||
'/settings': typeof AuthenticatedSettingsRouteLazyRouteWithChildren
|
||||
'/forgot-password': typeof authForgotPasswordLazyRoute
|
||||
'/sign-in-2': typeof authSignIn2LazyRoute
|
||||
'/sign-up': typeof authSignUpLazyRoute
|
||||
@ -548,18 +615,21 @@ export interface FileRoutesByFullPath {
|
||||
'/403': typeof errors403LazyRoute
|
||||
'/404': typeof errors404LazyRoute
|
||||
'/503': typeof errors503LazyRoute
|
||||
'/settings/account': typeof AuthenticatedSettingsAccountLazyRoute
|
||||
'/settings/appearance': typeof AuthenticatedSettingsAppearanceLazyRoute
|
||||
'/settings/display': typeof AuthenticatedSettingsDisplayLazyRoute
|
||||
'/settings/notifications': typeof AuthenticatedSettingsNotificationsLazyRoute
|
||||
'/dashboard/settings': typeof AuthenticatedDashboardSettingsRouteLazyRouteWithChildren
|
||||
'/dashboard': typeof AuthenticatedDashboardIndexRoute
|
||||
'/apps': typeof AuthenticatedAppsIndexLazyRoute
|
||||
'/chats': typeof AuthenticatedChatsIndexLazyRoute
|
||||
'/help-center': typeof AuthenticatedHelpCenterIndexLazyRoute
|
||||
'/nba': typeof AuthenticatedNbaIndexLazyRoute
|
||||
'/settings/': typeof AuthenticatedSettingsIndexLazyRoute
|
||||
'/tasks': typeof AuthenticatedTasksIndexLazyRoute
|
||||
'/users': typeof AuthenticatedUsersIndexLazyRoute
|
||||
'/dashboard/sales/coupons': typeof AuthenticatedDashboardSalesCouponsLazyRoute
|
||||
'/dashboard/sales/discounts': typeof AuthenticatedDashboardSalesDiscountsLazyRoute
|
||||
'/dashboard/settings/account': typeof AuthenticatedDashboardSettingsAccountLazyRoute
|
||||
'/dashboard/settings/appearance': typeof AuthenticatedDashboardSettingsAppearanceLazyRoute
|
||||
'/dashboard/settings/display': typeof AuthenticatedDashboardSettingsDisplayLazyRoute
|
||||
'/dashboard/settings/notifications': typeof AuthenticatedDashboardSettingsNotificationsLazyRoute
|
||||
'/dashboard/chats': typeof AuthenticatedDashboardChatsIndexLazyRoute
|
||||
'/dashboard/products': typeof AuthenticatedDashboardProductsIndexLazyRoute
|
||||
'/dashboard/sales': typeof AuthenticatedDashboardSalesIndexLazyRoute
|
||||
'/dashboard/settings/': typeof AuthenticatedDashboardSettingsIndexLazyRoute
|
||||
'/dashboard/tasks': typeof AuthenticatedDashboardTasksIndexLazyRoute
|
||||
'/dashboard/users': typeof AuthenticatedDashboardUsersIndexLazyRoute
|
||||
}
|
||||
|
||||
export interface FileRoutesByTo {
|
||||
@ -575,18 +645,20 @@ export interface FileRoutesByTo {
|
||||
'/403': typeof errors403LazyRoute
|
||||
'/404': typeof errors404LazyRoute
|
||||
'/503': typeof errors503LazyRoute
|
||||
'/settings/account': typeof AuthenticatedSettingsAccountLazyRoute
|
||||
'/settings/appearance': typeof AuthenticatedSettingsAppearanceLazyRoute
|
||||
'/settings/display': typeof AuthenticatedSettingsDisplayLazyRoute
|
||||
'/settings/notifications': typeof AuthenticatedSettingsNotificationsLazyRoute
|
||||
'/dashboard': typeof AuthenticatedDashboardIndexRoute
|
||||
'/apps': typeof AuthenticatedAppsIndexLazyRoute
|
||||
'/chats': typeof AuthenticatedChatsIndexLazyRoute
|
||||
'/help-center': typeof AuthenticatedHelpCenterIndexLazyRoute
|
||||
'/nba': typeof AuthenticatedNbaIndexLazyRoute
|
||||
'/settings': typeof AuthenticatedSettingsIndexLazyRoute
|
||||
'/tasks': typeof AuthenticatedTasksIndexLazyRoute
|
||||
'/users': typeof AuthenticatedUsersIndexLazyRoute
|
||||
'/dashboard/sales/coupons': typeof AuthenticatedDashboardSalesCouponsLazyRoute
|
||||
'/dashboard/sales/discounts': typeof AuthenticatedDashboardSalesDiscountsLazyRoute
|
||||
'/dashboard/settings/account': typeof AuthenticatedDashboardSettingsAccountLazyRoute
|
||||
'/dashboard/settings/appearance': typeof AuthenticatedDashboardSettingsAppearanceLazyRoute
|
||||
'/dashboard/settings/display': typeof AuthenticatedDashboardSettingsDisplayLazyRoute
|
||||
'/dashboard/settings/notifications': typeof AuthenticatedDashboardSettingsNotificationsLazyRoute
|
||||
'/dashboard/chats': typeof AuthenticatedDashboardChatsIndexLazyRoute
|
||||
'/dashboard/products': typeof AuthenticatedDashboardProductsIndexLazyRoute
|
||||
'/dashboard/sales': typeof AuthenticatedDashboardSalesIndexLazyRoute
|
||||
'/dashboard/settings': typeof AuthenticatedDashboardSettingsIndexLazyRoute
|
||||
'/dashboard/tasks': typeof AuthenticatedDashboardTasksIndexLazyRoute
|
||||
'/dashboard/users': typeof AuthenticatedDashboardUsersIndexLazyRoute
|
||||
}
|
||||
|
||||
export interface FileRoutesById {
|
||||
@ -596,7 +668,6 @@ export interface FileRoutesById {
|
||||
'/(auth)/500': typeof auth500Route
|
||||
'/(auth)/otp': typeof authOtpRoute
|
||||
'/(auth)/sign-in': typeof authSignInRoute
|
||||
'/_authenticated/settings': typeof AuthenticatedSettingsRouteLazyRouteWithChildren
|
||||
'/(auth)/forgot-password': typeof authForgotPasswordLazyRoute
|
||||
'/(auth)/sign-in-2': typeof authSignIn2LazyRoute
|
||||
'/(auth)/sign-up': typeof authSignUpLazyRoute
|
||||
@ -605,18 +676,21 @@ export interface FileRoutesById {
|
||||
'/(errors)/404': typeof errors404LazyRoute
|
||||
'/(errors)/500': typeof errors500LazyRoute
|
||||
'/(errors)/503': typeof errors503LazyRoute
|
||||
'/_authenticated/settings/account': typeof AuthenticatedSettingsAccountLazyRoute
|
||||
'/_authenticated/settings/appearance': typeof AuthenticatedSettingsAppearanceLazyRoute
|
||||
'/_authenticated/settings/display': typeof AuthenticatedSettingsDisplayLazyRoute
|
||||
'/_authenticated/settings/notifications': typeof AuthenticatedSettingsNotificationsLazyRoute
|
||||
'/_authenticated/dashboard/settings': typeof AuthenticatedDashboardSettingsRouteLazyRouteWithChildren
|
||||
'/_authenticated/dashboard/': typeof AuthenticatedDashboardIndexRoute
|
||||
'/_authenticated/apps/': typeof AuthenticatedAppsIndexLazyRoute
|
||||
'/_authenticated/chats/': typeof AuthenticatedChatsIndexLazyRoute
|
||||
'/_authenticated/help-center/': typeof AuthenticatedHelpCenterIndexLazyRoute
|
||||
'/_authenticated/nba/': typeof AuthenticatedNbaIndexLazyRoute
|
||||
'/_authenticated/settings/': typeof AuthenticatedSettingsIndexLazyRoute
|
||||
'/_authenticated/tasks/': typeof AuthenticatedTasksIndexLazyRoute
|
||||
'/_authenticated/users/': typeof AuthenticatedUsersIndexLazyRoute
|
||||
'/_authenticated/dashboard/sales/coupons': typeof AuthenticatedDashboardSalesCouponsLazyRoute
|
||||
'/_authenticated/dashboard/sales/discounts': typeof AuthenticatedDashboardSalesDiscountsLazyRoute
|
||||
'/_authenticated/dashboard/settings/account': typeof AuthenticatedDashboardSettingsAccountLazyRoute
|
||||
'/_authenticated/dashboard/settings/appearance': typeof AuthenticatedDashboardSettingsAppearanceLazyRoute
|
||||
'/_authenticated/dashboard/settings/display': typeof AuthenticatedDashboardSettingsDisplayLazyRoute
|
||||
'/_authenticated/dashboard/settings/notifications': typeof AuthenticatedDashboardSettingsNotificationsLazyRoute
|
||||
'/_authenticated/dashboard/chats/': typeof AuthenticatedDashboardChatsIndexLazyRoute
|
||||
'/_authenticated/dashboard/products/': typeof AuthenticatedDashboardProductsIndexLazyRoute
|
||||
'/_authenticated/dashboard/sales/': typeof AuthenticatedDashboardSalesIndexLazyRoute
|
||||
'/_authenticated/dashboard/settings/': typeof AuthenticatedDashboardSettingsIndexLazyRoute
|
||||
'/_authenticated/dashboard/tasks/': typeof AuthenticatedDashboardTasksIndexLazyRoute
|
||||
'/_authenticated/dashboard/users/': typeof AuthenticatedDashboardUsersIndexLazyRoute
|
||||
}
|
||||
|
||||
export interface FileRouteTypes {
|
||||
@ -627,7 +701,6 @@ export interface FileRouteTypes {
|
||||
| '/500'
|
||||
| '/otp'
|
||||
| '/sign-in'
|
||||
| '/settings'
|
||||
| '/forgot-password'
|
||||
| '/sign-in-2'
|
||||
| '/sign-up'
|
||||
@ -635,18 +708,21 @@ export interface FileRouteTypes {
|
||||
| '/403'
|
||||
| '/404'
|
||||
| '/503'
|
||||
| '/settings/account'
|
||||
| '/settings/appearance'
|
||||
| '/settings/display'
|
||||
| '/settings/notifications'
|
||||
| '/dashboard/settings'
|
||||
| '/dashboard'
|
||||
| '/apps'
|
||||
| '/chats'
|
||||
| '/help-center'
|
||||
| '/nba'
|
||||
| '/settings/'
|
||||
| '/tasks'
|
||||
| '/users'
|
||||
| '/dashboard/sales/coupons'
|
||||
| '/dashboard/sales/discounts'
|
||||
| '/dashboard/settings/account'
|
||||
| '/dashboard/settings/appearance'
|
||||
| '/dashboard/settings/display'
|
||||
| '/dashboard/settings/notifications'
|
||||
| '/dashboard/chats'
|
||||
| '/dashboard/products'
|
||||
| '/dashboard/sales'
|
||||
| '/dashboard/settings/'
|
||||
| '/dashboard/tasks'
|
||||
| '/dashboard/users'
|
||||
fileRoutesByTo: FileRoutesByTo
|
||||
to:
|
||||
| '/'
|
||||
@ -661,18 +737,20 @@ export interface FileRouteTypes {
|
||||
| '/403'
|
||||
| '/404'
|
||||
| '/503'
|
||||
| '/settings/account'
|
||||
| '/settings/appearance'
|
||||
| '/settings/display'
|
||||
| '/settings/notifications'
|
||||
| '/dashboard'
|
||||
| '/apps'
|
||||
| '/chats'
|
||||
| '/help-center'
|
||||
| '/nba'
|
||||
| '/settings'
|
||||
| '/tasks'
|
||||
| '/users'
|
||||
| '/dashboard/sales/coupons'
|
||||
| '/dashboard/sales/discounts'
|
||||
| '/dashboard/settings/account'
|
||||
| '/dashboard/settings/appearance'
|
||||
| '/dashboard/settings/display'
|
||||
| '/dashboard/settings/notifications'
|
||||
| '/dashboard/chats'
|
||||
| '/dashboard/products'
|
||||
| '/dashboard/sales'
|
||||
| '/dashboard/settings'
|
||||
| '/dashboard/tasks'
|
||||
| '/dashboard/users'
|
||||
id:
|
||||
| '__root__'
|
||||
| '/'
|
||||
@ -680,7 +758,6 @@ export interface FileRouteTypes {
|
||||
| '/(auth)/500'
|
||||
| '/(auth)/otp'
|
||||
| '/(auth)/sign-in'
|
||||
| '/_authenticated/settings'
|
||||
| '/(auth)/forgot-password'
|
||||
| '/(auth)/sign-in-2'
|
||||
| '/(auth)/sign-up'
|
||||
@ -689,18 +766,21 @@ export interface FileRouteTypes {
|
||||
| '/(errors)/404'
|
||||
| '/(errors)/500'
|
||||
| '/(errors)/503'
|
||||
| '/_authenticated/settings/account'
|
||||
| '/_authenticated/settings/appearance'
|
||||
| '/_authenticated/settings/display'
|
||||
| '/_authenticated/settings/notifications'
|
||||
| '/_authenticated/dashboard/settings'
|
||||
| '/_authenticated/dashboard/'
|
||||
| '/_authenticated/apps/'
|
||||
| '/_authenticated/chats/'
|
||||
| '/_authenticated/help-center/'
|
||||
| '/_authenticated/nba/'
|
||||
| '/_authenticated/settings/'
|
||||
| '/_authenticated/tasks/'
|
||||
| '/_authenticated/users/'
|
||||
| '/_authenticated/dashboard/sales/coupons'
|
||||
| '/_authenticated/dashboard/sales/discounts'
|
||||
| '/_authenticated/dashboard/settings/account'
|
||||
| '/_authenticated/dashboard/settings/appearance'
|
||||
| '/_authenticated/dashboard/settings/display'
|
||||
| '/_authenticated/dashboard/settings/notifications'
|
||||
| '/_authenticated/dashboard/chats/'
|
||||
| '/_authenticated/dashboard/products/'
|
||||
| '/_authenticated/dashboard/sales/'
|
||||
| '/_authenticated/dashboard/settings/'
|
||||
| '/_authenticated/dashboard/tasks/'
|
||||
| '/_authenticated/dashboard/users/'
|
||||
fileRoutesById: FileRoutesById
|
||||
}
|
||||
|
||||
@ -767,14 +847,16 @@ export const routeTree = rootRoute
|
||||
"/_authenticated": {
|
||||
"filePath": "_authenticated/route.tsx",
|
||||
"children": [
|
||||
"/_authenticated/settings",
|
||||
"/_authenticated/dashboard/settings",
|
||||
"/_authenticated/dashboard/",
|
||||
"/_authenticated/apps/",
|
||||
"/_authenticated/chats/",
|
||||
"/_authenticated/help-center/",
|
||||
"/_authenticated/nba/",
|
||||
"/_authenticated/tasks/",
|
||||
"/_authenticated/users/"
|
||||
"/_authenticated/dashboard/sales/coupons",
|
||||
"/_authenticated/dashboard/sales/discounts",
|
||||
"/_authenticated/dashboard/chats/",
|
||||
"/_authenticated/dashboard/products/",
|
||||
"/_authenticated/dashboard/sales/",
|
||||
"/_authenticated/dashboard/tasks/",
|
||||
"/_authenticated/dashboard/users/"
|
||||
]
|
||||
},
|
||||
"/(auth)/500": {
|
||||
@ -786,17 +868,6 @@ export const routeTree = rootRoute
|
||||
"/(auth)/sign-in": {
|
||||
"filePath": "(auth)/sign-in.tsx"
|
||||
},
|
||||
"/_authenticated/settings": {
|
||||
"filePath": "_authenticated/settings/route.lazy.tsx",
|
||||
"parent": "/_authenticated",
|
||||
"children": [
|
||||
"/_authenticated/settings/account",
|
||||
"/_authenticated/settings/appearance",
|
||||
"/_authenticated/settings/display",
|
||||
"/_authenticated/settings/notifications",
|
||||
"/_authenticated/settings/"
|
||||
]
|
||||
},
|
||||
"/(auth)/forgot-password": {
|
||||
"filePath": "(auth)/forgot-password.lazy.tsx"
|
||||
},
|
||||
@ -821,52 +892,71 @@ export const routeTree = rootRoute
|
||||
"/(errors)/503": {
|
||||
"filePath": "(errors)/503.lazy.tsx"
|
||||
},
|
||||
"/_authenticated/settings/account": {
|
||||
"filePath": "_authenticated/settings/account.lazy.tsx",
|
||||
"parent": "/_authenticated/settings"
|
||||
},
|
||||
"/_authenticated/settings/appearance": {
|
||||
"filePath": "_authenticated/settings/appearance.lazy.tsx",
|
||||
"parent": "/_authenticated/settings"
|
||||
},
|
||||
"/_authenticated/settings/display": {
|
||||
"filePath": "_authenticated/settings/display.lazy.tsx",
|
||||
"parent": "/_authenticated/settings"
|
||||
},
|
||||
"/_authenticated/settings/notifications": {
|
||||
"filePath": "_authenticated/settings/notifications.lazy.tsx",
|
||||
"parent": "/_authenticated/settings"
|
||||
"/_authenticated/dashboard/settings": {
|
||||
"filePath": "_authenticated/dashboard/settings/route.lazy.tsx",
|
||||
"parent": "/_authenticated",
|
||||
"children": [
|
||||
"/_authenticated/dashboard/settings/account",
|
||||
"/_authenticated/dashboard/settings/appearance",
|
||||
"/_authenticated/dashboard/settings/display",
|
||||
"/_authenticated/dashboard/settings/notifications",
|
||||
"/_authenticated/dashboard/settings/"
|
||||
]
|
||||
},
|
||||
"/_authenticated/dashboard/": {
|
||||
"filePath": "_authenticated/dashboard/index.tsx",
|
||||
"parent": "/_authenticated"
|
||||
},
|
||||
"/_authenticated/apps/": {
|
||||
"filePath": "_authenticated/apps/index.lazy.tsx",
|
||||
"parent": "/_authenticated"
|
||||
},
|
||||
"/_authenticated/chats/": {
|
||||
"filePath": "_authenticated/chats/index.lazy.tsx",
|
||||
"parent": "/_authenticated"
|
||||
},
|
||||
"/_authenticated/help-center/": {
|
||||
"filePath": "_authenticated/help-center/index.lazy.tsx",
|
||||
"parent": "/_authenticated"
|
||||
},
|
||||
"/_authenticated/nba/": {
|
||||
"filePath": "_authenticated/nba/index.lazy.tsx",
|
||||
"/_authenticated/dashboard/sales/coupons": {
|
||||
"filePath": "_authenticated/dashboard/sales/coupons.lazy.tsx",
|
||||
"parent": "/_authenticated"
|
||||
},
|
||||
"/_authenticated/settings/": {
|
||||
"filePath": "_authenticated/settings/index.lazy.tsx",
|
||||
"parent": "/_authenticated/settings"
|
||||
},
|
||||
"/_authenticated/tasks/": {
|
||||
"filePath": "_authenticated/tasks/index.lazy.tsx",
|
||||
"/_authenticated/dashboard/sales/discounts": {
|
||||
"filePath": "_authenticated/dashboard/sales/discounts.lazy.tsx",
|
||||
"parent": "/_authenticated"
|
||||
},
|
||||
"/_authenticated/users/": {
|
||||
"filePath": "_authenticated/users/index.lazy.tsx",
|
||||
"/_authenticated/dashboard/settings/account": {
|
||||
"filePath": "_authenticated/dashboard/settings/account.lazy.tsx",
|
||||
"parent": "/_authenticated/dashboard/settings"
|
||||
},
|
||||
"/_authenticated/dashboard/settings/appearance": {
|
||||
"filePath": "_authenticated/dashboard/settings/appearance.lazy.tsx",
|
||||
"parent": "/_authenticated/dashboard/settings"
|
||||
},
|
||||
"/_authenticated/dashboard/settings/display": {
|
||||
"filePath": "_authenticated/dashboard/settings/display.lazy.tsx",
|
||||
"parent": "/_authenticated/dashboard/settings"
|
||||
},
|
||||
"/_authenticated/dashboard/settings/notifications": {
|
||||
"filePath": "_authenticated/dashboard/settings/notifications.lazy.tsx",
|
||||
"parent": "/_authenticated/dashboard/settings"
|
||||
},
|
||||
"/_authenticated/dashboard/chats/": {
|
||||
"filePath": "_authenticated/dashboard/chats/index.lazy.tsx",
|
||||
"parent": "/_authenticated"
|
||||
},
|
||||
"/_authenticated/dashboard/products/": {
|
||||
"filePath": "_authenticated/dashboard/products/index.lazy.tsx",
|
||||
"parent": "/_authenticated"
|
||||
},
|
||||
"/_authenticated/dashboard/sales/": {
|
||||
"filePath": "_authenticated/dashboard/sales/index.lazy.tsx",
|
||||
"parent": "/_authenticated"
|
||||
},
|
||||
"/_authenticated/dashboard/settings/": {
|
||||
"filePath": "_authenticated/dashboard/settings/index.lazy.tsx",
|
||||
"parent": "/_authenticated/dashboard/settings"
|
||||
},
|
||||
"/_authenticated/dashboard/tasks/": {
|
||||
"filePath": "_authenticated/dashboard/tasks/index.lazy.tsx",
|
||||
"parent": "/_authenticated"
|
||||
},
|
||||
"/_authenticated/dashboard/users/": {
|
||||
"filePath": "_authenticated/dashboard/users/index.lazy.tsx",
|
||||
"parent": "/_authenticated"
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,14 @@
|
||||
import { createFileRoute } from "@tanstack/react-router";
|
||||
import { createFileRoute, redirect } from "@tanstack/react-router";
|
||||
import SignIn from "@/pages/auth/sign-in";
|
||||
import { isLoggedIn } from "@/hooks/useAuth";
|
||||
|
||||
export const Route = createFileRoute("/(auth)/sign-in")({
|
||||
component: SignIn
|
||||
component: SignIn,
|
||||
beforeLoad: async() => {
|
||||
if(isLoggedIn()) {
|
||||
throw redirect({
|
||||
to:"/dashboard"
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1,6 +0,0 @@
|
||||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
import Apps from "@/pages/apps";
|
||||
|
||||
export const Route = createLazyFileRoute("/_authenticated/apps/")({
|
||||
component: Apps
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
import Chats from "@/pages/chats";
|
||||
|
||||
export const Route = createLazyFileRoute("/_authenticated/chats/")({
|
||||
export const Route = createLazyFileRoute("/_authenticated/dashboard/chats/")({
|
||||
component: Chats
|
||||
});
|
@ -0,0 +1,6 @@
|
||||
import Products from '@/pages/products'
|
||||
import { createLazyFileRoute } from '@tanstack/react-router'
|
||||
|
||||
export const Route = createLazyFileRoute('/_authenticated/dashboard/products/')({
|
||||
component: Products,
|
||||
})
|
@ -0,0 +1,11 @@
|
||||
import { createLazyFileRoute } from '@tanstack/react-router'
|
||||
|
||||
export const Route = createLazyFileRoute(
|
||||
'/_authenticated/dashboard/sales/coupons',
|
||||
)({
|
||||
component: RouteComponent,
|
||||
})
|
||||
|
||||
function RouteComponent() {
|
||||
return <div>Hello "/_authenticated/dashboard/discounts/coupons"!</div>
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
import { createLazyFileRoute } from '@tanstack/react-router'
|
||||
|
||||
export const Route = createLazyFileRoute(
|
||||
'/_authenticated/dashboard/sales/discounts',
|
||||
)({
|
||||
component: RouteComponent,
|
||||
})
|
||||
|
||||
function RouteComponent() {
|
||||
return <div>Hello "/_authenticated/dashboard/discounts/discounts"!</div>
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
import { createLazyFileRoute } from '@tanstack/react-router'
|
||||
|
||||
export const Route = createLazyFileRoute(
|
||||
'/_authenticated/dashboard/sales/',
|
||||
)({
|
||||
component: RouteComponent,
|
||||
})
|
||||
|
||||
function RouteComponent() {
|
||||
return <div>Hello "/_authenticated/dashboard/discounts/"!</div>
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
import SettingsAccount from "@/pages/settings/account";
|
||||
|
||||
export const Route = createLazyFileRoute("/_authenticated/settings/account")({
|
||||
export const Route = createLazyFileRoute("/_authenticated/dashboard/settings/account")({
|
||||
component: SettingsAccount
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
import SettingsAppearance from "@/pages/settings/appearance";
|
||||
|
||||
export const Route = createLazyFileRoute("/_authenticated/settings/appearance")(
|
||||
export const Route = createLazyFileRoute("/_authenticated/dashboard/settings/appearance")(
|
||||
{ component: SettingsAppearance }
|
||||
);
|
@ -1,6 +1,6 @@
|
||||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
import SettingsDisplay from "@/pages/settings/display";
|
||||
|
||||
export const Route = createLazyFileRoute("/_authenticated/settings/display")({
|
||||
export const Route = createLazyFileRoute("/_authenticated/dashboard/settings/display")({
|
||||
component: SettingsDisplay
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
import SettingsProfile from "@/pages/settings/profile";
|
||||
|
||||
export const Route = createLazyFileRoute("/_authenticated/settings/")({
|
||||
export const Route = createLazyFileRoute("/_authenticated/dashboard/settings/")({
|
||||
component: SettingsProfile
|
||||
});
|
@ -2,7 +2,7 @@ import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
import SettingsNotifications from "@/pages/settings/notifications";
|
||||
|
||||
export const Route = createLazyFileRoute(
|
||||
"/_authenticated/settings/notifications"
|
||||
"/_authenticated/dashboard/settings/notifications"
|
||||
)({
|
||||
component: SettingsNotifications
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
import Settings from "@/pages/settings";
|
||||
|
||||
export const Route = createLazyFileRoute("/_authenticated/settings")({
|
||||
export const Route = createLazyFileRoute("/_authenticated/dashboard/settings")({
|
||||
component: Settings
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
import Tasks from "@/pages/tasks";
|
||||
|
||||
export const Route = createLazyFileRoute("/_authenticated/tasks/")({
|
||||
export const Route = createLazyFileRoute("/_authenticated/dashboard/tasks/")({
|
||||
component: Tasks
|
||||
});
|
@ -1,6 +1,6 @@
|
||||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
import Users from "@/pages/users";
|
||||
|
||||
export const Route = createLazyFileRoute("/_authenticated/users/")({
|
||||
export const Route = createLazyFileRoute("/_authenticated/dashboard/users/")({
|
||||
component: Users
|
||||
});
|
@ -1,6 +0,0 @@
|
||||
import { createLazyFileRoute } from "@tanstack/react-router";
|
||||
import Nba from "@/pages/nba";
|
||||
|
||||
export const Route = createLazyFileRoute("/_authenticated/nba/")({
|
||||
component: Nba
|
||||
});
|
@ -5,12 +5,13 @@ import { SearchProvider } from "@/context/search-context";
|
||||
import { SidebarProvider } from "@/components/ui/sidebar";
|
||||
import { AppSidebar } from "@/components/layout/app-sidebar";
|
||||
import SkipToMain from "@/components/skip-to-main";
|
||||
import { isLoggedIn } from "@/hooks/useAuth";
|
||||
|
||||
export const Route = createFileRoute("/_authenticated")({
|
||||
beforeLoad: async ({ location }) => {
|
||||
if (false) {
|
||||
if(!isLoggedIn()) {
|
||||
throw redirect({
|
||||
to: "/401",
|
||||
to: "/sign-in",
|
||||
search: {
|
||||
redirect: location.href
|
||||
}
|
||||
|
11
scripts/generate-client.sh
Executable file
11
scripts/generate-client.sh
Executable file
@ -0,0 +1,11 @@
|
||||
#! /usr/bin/env bash
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
cd backend
|
||||
python -c "import app.main; import json; print(json.dumps(app.main.app.openapi()))" > ../openapi.json
|
||||
cd ..
|
||||
mv openapi.json frontend/
|
||||
cd frontend
|
||||
npm run generate-client
|
Loading…
x
Reference in New Issue
Block a user