Minor tweaks to sign up on frontend and database structure
This commit is contained in:
parent
d0690f2f06
commit
260bef98cd
@ -1,18 +1,26 @@
|
|||||||
|
from typing import Optional
|
||||||
|
|
||||||
from fastapi import APIRouter
|
from fastapi import APIRouter
|
||||||
|
|
||||||
from app.api.dependencies import CurrentOwnerUser, SessionDep
|
from app.api.dependencies import CurrentOwnerUser, SessionDep
|
||||||
from app.crud.shop_crud import create_shop
|
from app.crud.shop_crud import create_shop
|
||||||
from app.schemas.shop_schemas import ShopCreate
|
from app.schemas.shop_schemas import ShopCreate, ShopPublic
|
||||||
from app.schemas.user_schemas import Token
|
|
||||||
|
|
||||||
router = APIRouter(prefix="/shop", tags=["Dashboard"])
|
router = APIRouter(prefix="/shop", tags=["Dashboard"])
|
||||||
|
|
||||||
|
|
||||||
@router.post("", status_code=201)
|
@router.post("", status_code=201)
|
||||||
def register_new_shop(
|
async def register_new_shop(
|
||||||
session: SessionDep,
|
session: SessionDep,
|
||||||
current_user: CurrentOwnerUser,
|
current_user: CurrentOwnerUser,
|
||||||
shop_data: ShopCreate
|
shop_data: ShopCreate
|
||||||
) -> bool:
|
) -> bool:
|
||||||
create_shop(session, shop_data, current_user)
|
create_shop(session, shop_data, current_user)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
@router.get("")
|
||||||
|
async def get_owned_shop_info(
|
||||||
|
current_user: CurrentOwnerUser
|
||||||
|
) -> Optional[ShopPublic]:
|
||||||
|
return current_user.owned_shop
|
||||||
|
@ -31,7 +31,7 @@ def create_shop(session: Session, shop_data: ShopCreate, creator: User) -> None:
|
|||||||
description=shop_data.description,
|
description=shop_data.description,
|
||||||
status=ShopStatus.INACTIVE,
|
status=ShopStatus.INACTIVE,
|
||||||
contact_email=creator.email,
|
contact_email=creator.email,
|
||||||
phone_number=creator.phone_number,
|
contact_phone_number=creator.phone_number,
|
||||||
currency=shop_data.currency
|
currency=shop_data.currency
|
||||||
)
|
)
|
||||||
session.add(new_shop)
|
session.add(new_shop)
|
||||||
|
@ -21,7 +21,7 @@ class ShopLinkEntry(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class ShopLinks(BaseModel):
|
class ShopLinks(BaseModel):
|
||||||
links: list[ShopLinkEntry]
|
links: list[ShopLinkEntry] = []
|
||||||
|
|
||||||
|
|
||||||
class ShopBusinessHourEntry(BaseModel):
|
class ShopBusinessHourEntry(BaseModel):
|
||||||
@ -31,15 +31,15 @@ class ShopBusinessHourEntry(BaseModel):
|
|||||||
|
|
||||||
|
|
||||||
class ShopBusinessHours(BaseModel):
|
class ShopBusinessHours(BaseModel):
|
||||||
hours: list[ShopBusinessHourEntry]
|
hours: list[ShopBusinessHourEntry] = []
|
||||||
|
|
||||||
|
|
||||||
class ShopAddress(SQLModel):
|
class ShopAddress(SQLModel):
|
||||||
street: str = Field(max_length=255, nullable=False)
|
street: str = Field(default="", max_length=255, nullable=False)
|
||||||
city: str = Field(max_length=100, nullable=False)
|
city: str = Field(default="", max_length=100, nullable=False)
|
||||||
state: str = Field(max_length=100, nullable=True)
|
state: Optional[str] = Field(default=None, max_length=100, nullable=True)
|
||||||
postal_code: str = Field(max_length=20, nullable=False)
|
postal_code: str = Field(default="", max_length=20, nullable=False)
|
||||||
country: str = Field(max_length=100, nullable=False)
|
country: str = Field(default="", max_length=100, nullable=False)
|
||||||
|
|
||||||
|
|
||||||
class Shop(SQLModel, table=True):
|
class Shop(SQLModel, table=True):
|
||||||
@ -55,13 +55,19 @@ class Shop(SQLModel, table=True):
|
|||||||
status: ShopStatus = Field(sa_column=Column(Enum(ShopStatus)))
|
status: ShopStatus = Field(sa_column=Column(Enum(ShopStatus)))
|
||||||
logo: Optional[str] = Field(max_length=100)
|
logo: Optional[str] = Field(max_length=100)
|
||||||
contact_email: str = Field(max_length=128, nullable=False, unique=True)
|
contact_email: str = Field(max_length=128, nullable=False, unique=True)
|
||||||
phone_number: str = Field(max_length=15, nullable=False)
|
contact_phone_number: str = Field(max_length=15, nullable=False)
|
||||||
address: ShopAddress = Field(sa_column=Column(JSONB, nullable=False, default=lambda: {}))
|
address: ShopAddress = Field(
|
||||||
business_hours: ShopBusinessHours = Field(sa_column=Column(JSONB, nullable=False, default=lambda: {}))
|
sa_column=Column(JSONB, nullable=False, default=lambda: ShopAddress().dict())
|
||||||
links: ShopLinks = Field(sa_column=Column(JSONB, nullable=False, default=lambda: {}))
|
)
|
||||||
|
business_hours: ShopBusinessHours = Field(
|
||||||
|
sa_column=Column(JSONB, nullable=False, default=lambda: ShopBusinessHours().dict())
|
||||||
|
)
|
||||||
|
links: ShopLinks = Field(
|
||||||
|
sa_column=Column(JSONB, nullable=False, default=lambda: ShopLinks().dict())
|
||||||
|
)
|
||||||
currency: str = Field(max_length=3, nullable=False)
|
currency: str = Field(max_length=3, nullable=False)
|
||||||
|
|
||||||
owner: Optional["User"] = Relationship(
|
owner: "User" = Relationship(
|
||||||
back_populates='owned_shop',
|
back_populates='owned_shop',
|
||||||
sa_relationship_kwargs={"foreign_keys": "[Shop.owner_id]"}
|
sa_relationship_kwargs={"foreign_keys": "[Shop.owner_id]"}
|
||||||
)
|
)
|
||||||
@ -71,11 +77,5 @@ class Shop(SQLModel, table=True):
|
|||||||
sa_relationship_kwargs={"foreign_keys": "[User.shop_id]"}
|
sa_relationship_kwargs={"foreign_keys": "[User.shop_id]"}
|
||||||
)
|
)
|
||||||
|
|
||||||
# __table_args__ = (
|
|
||||||
# CheckConstraint("business_hours ? 'hours'", name="check_business_hours_keys"),
|
|
||||||
# CheckConstraint("links ? 'links'", name="check_links_keys"),
|
|
||||||
# CheckConstraint("address ? 'address'", name="check_address_keys")
|
|
||||||
# )
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["Shop", "ShopBusinessHours", "ShopLinks", "ShopStatus"]
|
__all__ = ["Shop", "ShopBusinessHours", "ShopLinks", "ShopStatus"]
|
||||||
|
@ -31,7 +31,7 @@ class User(SQLModel, table=True):
|
|||||||
password: str = Field(max_length=60, nullable=False)
|
password: str = Field(max_length=60, nullable=False)
|
||||||
first_name: Optional[str] = Field(max_length=64)
|
first_name: Optional[str] = Field(max_length=64)
|
||||||
last_name: Optional[str] = Field(max_length=64)
|
last_name: Optional[str] = Field(max_length=64)
|
||||||
phone_number: str = Field(max_length=15, nullable=False)
|
phone_number: str = Field(max_length=16, nullable=False)
|
||||||
profile_picture: Optional[str] = Field(max_length=100)
|
profile_picture: Optional[str] = Field(max_length=100)
|
||||||
created_at: datetime = Field(default_factory=datetime.utcnow, nullable=False)
|
created_at: datetime = Field(default_factory=datetime.utcnow, nullable=False)
|
||||||
updated_at: datetime = Field(default_factory=datetime.utcnow, nullable=False)
|
updated_at: datetime = Field(default_factory=datetime.utcnow, nullable=False)
|
||||||
|
@ -1,14 +1,27 @@
|
|||||||
|
|
||||||
from pydantic import EmailStr
|
from datetime import datetime
|
||||||
from sqlmodel import Field, SQLModel
|
from pydantic import EmailStr, BaseModel, Field
|
||||||
|
from sqlmodel import SQLModel
|
||||||
|
|
||||||
from app.database.models.shop_model import ShopAddress
|
from app.database.models.shop_model import ShopAddress, ShopStatus, ShopBusinessHours, ShopLinks
|
||||||
|
|
||||||
|
|
||||||
class ShopCreate(SQLModel):
|
class ShopCreate(BaseModel):
|
||||||
name: str = Field(max_length=100, nullable=False, unique=True)
|
name: str = Field(max_length=100, nullable=False, unique=True)
|
||||||
description: str = Field(max_length=500, nullable=False)
|
description: str = Field(max_length=500, nullable=False)
|
||||||
currency: str = Field(max_length=3, nullable=False)
|
currency: str = Field(max_length=3, nullable=False)
|
||||||
contact_email: EmailStr = Field()
|
contact_email: EmailStr = Field()
|
||||||
contact_phone_number: str = Field(min_length=2, max_length=16, schema_extra={"pattern": r'^\+[1-9]\d{1,14}$'})
|
contact_phone_number: str = Field(min_length=2, max_length=16, pattern=r'^\+[1-9]\d{1,14}$')
|
||||||
address: ShopAddress
|
address: ShopAddress
|
||||||
|
|
||||||
|
|
||||||
|
class ShopPublic(BaseModel):
|
||||||
|
name: str
|
||||||
|
description: str
|
||||||
|
currency: str
|
||||||
|
contact_email: EmailStr
|
||||||
|
contact_phone_number: str
|
||||||
|
address: ShopAddress
|
||||||
|
business_hours: ShopBusinessHours
|
||||||
|
links: ShopLinks
|
||||||
|
status: ShopStatus
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
VITE_API_URL=
|
984
frontend/package-lock.json
generated
984
frontend/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
0
frontend/src/hooks/useShop.ts
Normal file
0
frontend/src/hooks/useShop.ts
Normal file
@ -14,10 +14,9 @@ import {
|
|||||||
} from "@/components/ui/form";
|
} from "@/components/ui/form";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
import { PasswordInput } from "@/components/password-input";
|
import { PasswordInput } from "@/components/password-input";
|
||||||
import { registerUser } from "@/lib/api";
|
|
||||||
import { ApiError } from "@/errors/api-error";
|
|
||||||
import useAuth from "@/hooks/useAuth";
|
import useAuth from "@/hooks/useAuth";
|
||||||
import { PhoneInput } from "@/components/ui/phone-number-input";
|
import { PhoneInput } from "@/components/ui/phone-number-input";
|
||||||
|
import { toast } from "@/hooks/useToast";
|
||||||
|
|
||||||
type SignUpFormProps = HTMLAttributes<HTMLDivElement>;
|
type SignUpFormProps = HTMLAttributes<HTMLDivElement>;
|
||||||
|
|
||||||
@ -68,8 +67,6 @@ const formSchema = z
|
|||||||
export function SignUpForm({ className, ...props }: SignUpFormProps) {
|
export function SignUpForm({ className, ...props }: SignUpFormProps) {
|
||||||
const { signUpMutation } = useAuth();
|
const { signUpMutation } = useAuth();
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
|
||||||
const [successMessage, setSuccessMessage] = useState<string | null>(null);
|
|
||||||
|
|
||||||
const form = useForm<z.infer<typeof formSchema>>({
|
const form = useForm<z.infer<typeof formSchema>>({
|
||||||
resolver: zodResolver(formSchema),
|
resolver: zodResolver(formSchema),
|
||||||
@ -84,17 +81,11 @@ export function SignUpForm({ className, ...props }: SignUpFormProps) {
|
|||||||
|
|
||||||
async function onSubmit(data: z.infer<typeof formSchema>) {
|
async function onSubmit(data: z.infer<typeof formSchema>) {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
setError(null);
|
signUpMutation.mutate(data);
|
||||||
setSuccessMessage(null);
|
toast({
|
||||||
|
title: "Successfully registered"
|
||||||
try {
|
});
|
||||||
signUpMutation.mutate(data);
|
setIsLoading(false);
|
||||||
setSuccessMessage("Account created successfully!");
|
|
||||||
} catch (error: unknown) {
|
|
||||||
setError(error instanceof ApiError ? error.response : "Something went wrong.");
|
|
||||||
} finally {
|
|
||||||
setIsLoading(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -167,10 +158,6 @@ export function SignUpForm({ className, ...props }: SignUpFormProps) {
|
|||||||
</FormItem>
|
</FormItem>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
{error && <p className="text-red-500">{error}</p>}
|
|
||||||
{successMessage && (
|
|
||||||
<p className="text-green-500">{successMessage}</p>
|
|
||||||
)}
|
|
||||||
<Button className="mt-2" type="submit" disabled={isLoading}>
|
<Button className="mt-2" type="submit" disabled={isLoading}>
|
||||||
{isLoading ? "Creating Account..." : "Create Account"}
|
{isLoading ? "Creating Account..." : "Create Account"}
|
||||||
</Button>
|
</Button>
|
||||||
|
@ -12,11 +12,5 @@ export default defineConfig({
|
|||||||
alias: {
|
alias: {
|
||||||
"@": path.resolve(__dirname, "./src"),
|
"@": path.resolve(__dirname, "./src"),
|
||||||
},
|
},
|
||||||
},
|
|
||||||
server: {
|
|
||||||
port: 31713
|
|
||||||
},
|
|
||||||
preview: {
|
|
||||||
port: 37173
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user