Skip to content

Commit

Permalink
Added extensive logging for listing creation and improved various UIs (
Browse files Browse the repository at this point in the history
  • Loading branch information
Winston-Hsiao authored Nov 12, 2024
1 parent 056efbe commit f73e513
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 143 deletions.
8 changes: 6 additions & 2 deletions frontend/src/components/listing/ListingRegisterRobot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,20 @@ const ListingRegisterRobot = ({ listingId }: Props) => {
const [isRegisterModalOpen, setIsRegisterModalOpen] = useState(false);

return (
<div className="flex items-center gap-2 mt-2">
<div className="flex flex-col items-start gap-3 mt-2">
<Button
variant="default"
variant="outline"
className="flex items-center"
onClick={() => setIsRegisterModalOpen(true)}
>
<FaPlus className="mr-2 h-4 w-4" />
<span className="mr-2">Register Robot</span>
</Button>

<p className="text-xs text-gray-6">
You can interact with your registered robots in the terminal.
</p>

<RegisterRobotModal
isOpen={isRegisterModalOpen}
onClose={() => setIsRegisterModalOpen(false)}
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/listing/ListingRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ const ListingRenderer = ({ listing }: { listing: ListingResponse }) => {
const isForSale = priceAmount && stripeProductId && inventoryType;

return (
<div className="max-w-6xl mx-auto p-4 pt-12">
<div className="max-w-6xl mx-auto sm:p-4 sm:pt-8">
{/* Main content area - flex column on mobile, row on desktop */}
<div className="flex flex-col md:flex-row gap-8 mb-8">
<ListingImageFlipper
Expand Down
58 changes: 30 additions & 28 deletions frontend/src/components/pages/CreateSell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -215,40 +215,33 @@ const CreateSell = () => {
});
};

const onSubmit = async ({
name,
description,
slug,
price_amount,
currency,
inventory_type,
inventory_quantity,
preorder_release_date,
is_reservation,
reservation_deposit_amount,
}: SellListingType) => {
const onSubmit = async (data: SellListingType) => {
console.log("Submitting data:", data);
setIsSubmitting(true);

const formData = new FormData();
formData.append("name", name);
formData.append("description", description || "");
formData.append("slug", slug || slugify(name));
formData.append("name", data.name);
formData.append("description", data.description || "");
formData.append("slug", data.slug || slugify(data.name));
formData.append(
"price_amount",
price_amount ? convertToCents(price_amount).toString() : "",
data.price_amount ? convertToCents(data.price_amount).toString() : "",
);
formData.append("currency", data.currency);
formData.append("inventory_type", data.inventory_type);
formData.append(
"inventory_quantity",
data.inventory_quantity?.toString() || "",
);
formData.append("currency", currency);
formData.append("inventory_type", inventory_type);
formData.append("inventory_quantity", inventory_quantity?.toString() || "");
formData.append(
"preorder_release_date",
preorder_release_date?.toString() || "",
data.preorder_release_date?.toString() || "",
);
formData.append("is_reservation", is_reservation?.toString() || "");
formData.append("is_reservation", data.is_reservation?.toString() || "");
formData.append(
"reservation_deposit_amount",
reservation_deposit_amount
? convertToCents(reservation_deposit_amount).toString()
data.reservation_deposit_amount
? convertToCents(data.reservation_deposit_amount).toString()
: "",
);

Expand All @@ -260,10 +253,19 @@ const CreateSell = () => {
});

try {
// @ts-expect-error Server accepts FormData but TypeScript doesn't recognize it
const { data: responseData } = await auth.client.POST("/listings/add", {
body: formData,
} as { body: FormData });
const { data: responseData, error } = await auth.client.POST(
"/listings/add",
// @ts-expect-error Server accepts FormData but TypeScript doesn't recognize it
{
body: formData,
} as { body: FormData },
);

if (error) {
console.error("Server error:", error.detail);
addErrorAlert(`Failed to create listing: ${error.detail}`);
return;
}

if (responseData && responseData.username && responseData.slug) {
addAlert("New listing was created successfully", "success");
Expand All @@ -277,8 +279,8 @@ const CreateSell = () => {
throw new Error("Invalid response data");
}
} catch (error) {
addErrorAlert("Failed to create listing");
console.error("Error creating listing:", error);
addErrorAlert("Failed to create listing");
} finally {
setIsSubmitting(false);
}
Expand Down
26 changes: 18 additions & 8 deletions frontend/src/components/pages/SellerDashboard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { useAuthentication } from "@/hooks/useAuth";
import ROUTES from "@/lib/types/routes";
import { Check } from "lucide-react";

import { Button } from "../ui/button";

export default function SellerDashboard() {
const navigate = useNavigate();
const auth = useAuthentication();
Expand Down Expand Up @@ -52,14 +54,22 @@ export default function SellerDashboard() {
</div>

<div className="mt-6">
<a
href={`https://dashboard.stripe.com/${auth.currentUser?.stripe_connect_account_id}`}
target="_blank"
rel="noopener noreferrer"
className="bg-primary-9 text-primary-12 px-6 py-3 rounded-lg hover:bg-primary-12 hover:text-primary-9 inline-block"
>
Open Stripe Dashboard
</a>
<div className="flex gap-2 items-center">
<Button
variant="outline"
onClick={() => navigate(ROUTES.BOTS.SELL.path)}
>
Sell a Robot on K-Scale
</Button>
<a
href={`https://dashboard.stripe.com/${auth.currentUser?.stripe_connect_account_id}`}
target="_blank"
rel="noopener noreferrer"
className="bg-primary-9 text-primary-12 px-4 py-2 rounded-lg hover:bg-primary-12 hover:text-primary-9 inline-block"
>
Open Stripe Dashboard
</a>
</div>
</div>
</div>
</div>
Expand Down
192 changes: 88 additions & 104 deletions store/app/routers/listings.py
Original file line number Diff line number Diff line change
Expand Up @@ -287,124 +287,108 @@ async def add_listing(
reservation_deposit_amount: int | None = Form(None),
photos: List[UploadFile] = File(None),
) -> NewListingResponse:
logger.info(f"Received {len(photos) if photos else 0} photos")

# Initialize Stripe-related variables
stripe_product_id = None
stripe_price_id = None
deposit_price_id = None

# Validate the input
if price_amount is not None and price_amount <= 0:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Price amount must be greater than 0",
)

if inventory_type == "finite" and (inventory_quantity is None or inventory_quantity <= 0):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Finite inventory requires a positive quantity",
)

if inventory_type == "preorder" and not preorder_release_date:
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Preorder requires a release date",
)

if is_reservation and (not reservation_deposit_amount or reservation_deposit_amount <= 0):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Reservations require a deposit amount",
)
try:
logger.info("Starting to process add listing request")

if is_reservation and (
not price_amount or not reservation_deposit_amount or price_amount <= reservation_deposit_amount
):
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Full price must be greater than deposit amount",
)
# Initialize variables
stripe_product_id = None
stripe_price_id = None
deposit_price_id = None # Initialize here

# Create Stripe product if price is set
if price_amount is not None and user.stripe_connect_account_id:
try:
product = stripe.Product.create(
name=name,
description=description or "",
metadata={
"user_id": user.id,
},
stripe_account=user.stripe_connect_account_id,
# Validation checks
if price_amount is not None and price_amount <= 0:
logger.error("Validation failed: Price amount must be greater than 0")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail="Price amount must be greater than 0",
)

price = stripe.Price.create(
product=product.id,
currency=currency,
unit_amount=price_amount,
metadata={
"inventory_quantity": str(inventory_quantity) if inventory_type == "finite" else "",
"preorder_release_date": str(preorder_release_date) if inventory_type == "preorder" else "",
},
stripe_account=user.stripe_connect_account_id,
)
# Create Stripe product if price is set
if price_amount is not None and user.stripe_connect_account_id:
try:
product = stripe.Product.create(
name=name,
description=description or "",
metadata={
"user_id": user.id,
},
stripe_account=user.stripe_connect_account_id,
)

if is_reservation and reservation_deposit_amount:
deposit_price = stripe.Price.create(
price = stripe.Price.create(
product=product.id,
currency=currency,
unit_amount=reservation_deposit_amount,
metadata={"is_deposit": "true"},
unit_amount=price_amount,
metadata={
"inventory_quantity": str(inventory_quantity) if inventory_type == "finite" else "",
"preorder_release_date": str(preorder_release_date) if inventory_type == "preorder" else "",
},
stripe_account=user.stripe_connect_account_id,
)
deposit_price_id = deposit_price.id

stripe_product_id = product.id
stripe_price_id = price.id

except stripe.StripeError as e:
logger.error(f"Stripe error: {str(e)}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Error creating Stripe product: {str(e)}",
)
if is_reservation and reservation_deposit_amount:
deposit_price = stripe.Price.create(
product=product.id,
currency=currency,
unit_amount=reservation_deposit_amount,
metadata={"is_deposit": "true"},
stripe_account=user.stripe_connect_account_id,
)
deposit_price_id = deposit_price.id

# Create the listing
listing = Listing.create(
name=name,
description=description or "",
child_ids=child_ids.split(",") if child_ids else [],
slug=slug,
user_id=user.id,
price_amount=price_amount,
currency=currency,
inventory_type=inventory_type,
inventory_quantity=inventory_quantity,
preorder_release_date=preorder_release_date,
is_reservation=is_reservation,
reservation_deposit_amount=reservation_deposit_amount,
stripe_product_id=stripe_product_id,
stripe_price_id=stripe_price_id,
stripe_deposit_price_id=deposit_price_id,
)
stripe_product_id = product.id
stripe_price_id = price.id

await crud.add_listing(listing)

# Handle photo uploads
if photos:
for photo in photos:
if photo.filename:
await crud.upload_artifact(
name=photo.filename,
file=photo,
listing=listing,
artifact_type="image",
except stripe.StripeError as e:
logger.error(f"Stripe error: {str(e)}")
raise HTTPException(
status_code=status.HTTP_400_BAD_REQUEST,
detail=f"Error creating Stripe product: {str(e)}",
)
else:
logger.warning("Skipping photo upload due to missing filename")

return NewListingResponse(listing_id=listing.id, username=user.username, slug=slug)
# Create the listing
listing = Listing.create(
name=name,
description=description or "",
child_ids=child_ids.split(",") if child_ids else [],
slug=slug,
user_id=user.id,
price_amount=price_amount,
currency=currency,
inventory_type=inventory_type,
inventory_quantity=inventory_quantity,
preorder_release_date=preorder_release_date,
is_reservation=is_reservation,
reservation_deposit_amount=reservation_deposit_amount,
stripe_product_id=stripe_product_id,
stripe_price_id=stripe_price_id,
stripe_deposit_price_id=deposit_price_id,
)

await crud.add_listing(listing)
logger.info("Listing created successfully")

# Handle photo uploads
if photos:
for photo in photos:
if photo.filename:
await crud.upload_artifact(
name=photo.filename,
file=photo,
listing=listing,
artifact_type="image",
)
else:
logger.warning("Skipping photo upload due to missing filename")

return NewListingResponse(listing_id=listing.id, username=user.username, slug=slug)

except HTTPException as e:
logger.error(f"HTTPException: {e.detail}")
raise
except Exception as e:
logger.error(f"Unexpected error: {str(e)}")
raise HTTPException(status_code=500, detail="Internal server error")


@router.delete("/delete/{listing_id}", response_model=bool)
Expand Down

0 comments on commit f73e513

Please sign in to comment.