@tscircuit/runframe 0.0.347 → 0.0.348

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -988,7 +988,7 @@ var RenderLogViewer = ({
988
988
  };
989
989
 
990
990
  // package.json
991
- var version = "0.0.346";
991
+ var version = "0.0.347";
992
992
 
993
993
  // lib/components/CircuitJsonPreview/CircuitJsonPreview.tsx
994
994
  import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
@@ -1345,12 +1345,1140 @@ import { CadViewer as CadViewer2 } from "@tscircuit/3d-viewer";
1345
1345
  import { PCBViewer as PCBViewer3 } from "@tscircuit/pcb-viewer";
1346
1346
  import { SchematicViewer as SchematicViewer2 } from "@tscircuit/schematic-viewer";
1347
1347
 
1348
+ // lib/components/RunFrameWithApi/store.ts
1349
+ import { applyEditEventsToManualEditsFile } from "@tscircuit/core";
1350
+
1351
+ // lib/utils/debug.ts
1352
+ import Debug from "debug";
1353
+ var debug = Debug("run-frame");
1354
+ var debug_default = debug;
1355
+
1356
+ // lib/components/RunFrameWithApi/store.ts
1357
+ import { create } from "zustand";
1358
+ import { devtools } from "zustand/middleware";
1359
+
1360
+ // lib/components/RunFrameWithApi/api-base.ts
1361
+ var API_BASE = window.API_BASE_URL ?? "/api";
1362
+
1363
+ // lib/components/RunFrameWithApi/store.ts
1364
+ var debug2 = debug_default.extend("store");
1365
+ async function upsertFileApi(path, content) {
1366
+ const response = await fetch(`${API_BASE}/files/upsert`, {
1367
+ method: "POST",
1368
+ headers: { "Content-Type": "application/json" },
1369
+ body: JSON.stringify({ file_path: path, text_content: content })
1370
+ });
1371
+ const data = await response.json();
1372
+ return data.file;
1373
+ }
1374
+ async function getFileApi(path) {
1375
+ const response = await fetch(
1376
+ `${API_BASE}/files/get?file_path=${encodeURIComponent(path)}`
1377
+ );
1378
+ const data = await response.json();
1379
+ return data.file;
1380
+ }
1381
+ async function getEvents(since) {
1382
+ const url = since ? `${API_BASE}/events/list?since=${encodeURIComponent(since)}` : `${API_BASE}/events/list`;
1383
+ const response = await fetch(url);
1384
+ const data = await response.json();
1385
+ return data.event_list;
1386
+ }
1387
+ async function getInitialFilesApi() {
1388
+ const response = await fetch(`${API_BASE}/files/list`);
1389
+ const { file_list } = await response.json();
1390
+ const fileMap = /* @__PURE__ */ new Map();
1391
+ for (const file of file_list) {
1392
+ const fullFile = await getFileApi(file.file_path);
1393
+ fileMap.set(file.file_path, fullFile.text_content);
1394
+ }
1395
+ return fileMap;
1396
+ }
1397
+ var useRunFrameStore = create()(
1398
+ devtools(
1399
+ (set, get) => ({
1400
+ fsMap: /* @__PURE__ */ new Map(),
1401
+ lastEventTime: (/* @__PURE__ */ new Date()).toISOString(),
1402
+ isPolling: false,
1403
+ error: null,
1404
+ circuitJson: null,
1405
+ lastManualEditsChangeSentAt: 0,
1406
+ recentEvents: [],
1407
+ simulateScenarioOrder: void 0,
1408
+ loadInitialFiles: async () => {
1409
+ const fsMap = await getInitialFilesApi();
1410
+ debug2("loaded initial files", { fsMap });
1411
+ set({ fsMap });
1412
+ },
1413
+ upsertFile: async (path, content) => {
1414
+ try {
1415
+ const file = await upsertFileApi(path, content);
1416
+ set((state) => ({
1417
+ fsMap: new Map(state.fsMap).set(file.file_path, file.text_content)
1418
+ }));
1419
+ } catch (error) {
1420
+ set({ error });
1421
+ }
1422
+ },
1423
+ getFile: async (path) => {
1424
+ try {
1425
+ const file = await getFileApi(path);
1426
+ set((state) => ({
1427
+ fsMap: new Map(state.fsMap).set(file.file_path, file.text_content)
1428
+ }));
1429
+ } catch (error) {
1430
+ set({ error });
1431
+ }
1432
+ },
1433
+ setCircuitJson: (circuitJson) => {
1434
+ if (circuitJson === get().circuitJson) return;
1435
+ set({ circuitJson });
1436
+ },
1437
+ startPolling: () => {
1438
+ const poll = async () => {
1439
+ const state = get();
1440
+ if (!state.isPolling) return;
1441
+ try {
1442
+ const events = await getEvents(state.lastEventTime);
1443
+ if (events.length > 0) {
1444
+ set((state2) => ({
1445
+ recentEvents: [...state2.recentEvents, ...events].slice(0, 100)
1446
+ // TODO sort
1447
+ // .sort((a, b) => b.created_at.localeCompare(a.created_at)),
1448
+ }));
1449
+ const newLastEventTime = events[events.length - 1].created_at;
1450
+ const updates = new Map(state.fsMap);
1451
+ for (const event of events) {
1452
+ if (event.event_type === "FILE_UPDATED") {
1453
+ const file = await getFileApi(event.file_path);
1454
+ if (event.file_path === "manual_edits.json" && Date.now() - state.lastManualEditsChangeSentAt < 1e3) {
1455
+ continue;
1456
+ }
1457
+ updates.set(file.file_path, file.text_content);
1458
+ }
1459
+ }
1460
+ set({
1461
+ fsMap: updates,
1462
+ lastEventTime: newLastEventTime
1463
+ });
1464
+ }
1465
+ } catch (error) {
1466
+ set({ error });
1467
+ }
1468
+ setTimeout(poll, 1e3);
1469
+ };
1470
+ set({ isPolling: true });
1471
+ poll();
1472
+ },
1473
+ stopPolling: () => {
1474
+ set({ isPolling: false });
1475
+ },
1476
+ pushEvent: async (event) => {
1477
+ await fetch(`${window.API_BASE_URL ?? ""}/api/events/create`, {
1478
+ method: "POST",
1479
+ headers: {
1480
+ "Content-Type": "application/json"
1481
+ },
1482
+ body: JSON.stringify(event)
1483
+ });
1484
+ },
1485
+ applyEditEventsAndUpdateManualEditsJson: async (editEvents) => {
1486
+ debug2("applyEditEventsAndUpdateManualEditsJson", { editEvents });
1487
+ const state = get();
1488
+ if (!state.circuitJson) return;
1489
+ const manualEditsJson = state.fsMap.get("manual-edits.json");
1490
+ const manualEdits = manualEditsJson ? JSON.parse(manualEditsJson) : {};
1491
+ const updatedManualEditsFileContent = applyEditEventsToManualEditsFile({
1492
+ circuitJson: state.circuitJson,
1493
+ editEvents,
1494
+ manualEditsFile: manualEdits
1495
+ });
1496
+ debug2("updatedManualEditsFileContent", updatedManualEditsFileContent);
1497
+ set((state2) => ({
1498
+ lastManualEditsChangeSentAt: Date.now(),
1499
+ fsMap: new Map(state2.fsMap).set(
1500
+ "manual-edits.json",
1501
+ JSON.stringify(updatedManualEditsFileContent)
1502
+ )
1503
+ }));
1504
+ await upsertFileApi(
1505
+ "manual-edits.json",
1506
+ JSON.stringify(updatedManualEditsFileContent, null, 2)
1507
+ );
1508
+ },
1509
+ setSimulateScenarioOrder: (scenarioOrder) => set({ simulateScenarioOrder: scenarioOrder })
1510
+ }),
1511
+ { name: "run-frame-store" }
1512
+ )
1513
+ );
1514
+
1515
+ // lib/components/ui/alert-dialog.tsx
1516
+ import * as React6 from "react";
1517
+ import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
1518
+ import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1519
+ var AlertDialog = AlertDialogPrimitive.Root;
1520
+ var AlertDialogPortal = AlertDialogPrimitive.Portal;
1521
+ var AlertDialogOverlay = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx17(
1522
+ AlertDialogPrimitive.Overlay,
1523
+ {
1524
+ className: cn(
1525
+ "rf-fixed rf-inset-0 rf-z-50 rf-bg-black/80 data-[state=open]:rf-animate-in data-[state=closed]:rf-animate-out data-[state=closed]:rf-fade-out-0 data-[state=open]:rf-fade-in-0",
1526
+ className
1527
+ ),
1528
+ ...props,
1529
+ ref
1530
+ }
1531
+ ));
1532
+ AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
1533
+ var AlertDialogContent = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsxs13(AlertDialogPortal, { children: [
1534
+ /* @__PURE__ */ jsx17(AlertDialogOverlay, {}),
1535
+ /* @__PURE__ */ jsx17(
1536
+ AlertDialogPrimitive.Content,
1537
+ {
1538
+ ref,
1539
+ className: cn(
1540
+ "rf-fixed rf-left-[50%] rf-top-[50%] rf-z-50 rf-grid rf-w-full rf-max-w-lg rf-translate-x-[-50%] rf-translate-y-[-50%] rf-gap-4 rf-border rf-border-zinc-200 rf-bg-white rf-p-6 rf-shadow-lg rf-duration-200 data-[state=open]:rf-animate-in data-[state=closed]:rf-animate-out data-[state=closed]:rf-fade-out-0 data-[state=open]:rf-fade-in-0 data-[state=closed]:rf-zoom-out-95 data-[state=open]:rf-zoom-in-95 data-[state=closed]:rf-slide-out-to-left-1/2 data-[state=closed]:rf-slide-out-to-top-[48%] data-[state=open]:rf-slide-in-from-left-1/2 data-[state=open]:rf-slide-in-from-top-[48%] sm:rf-rounded-lg dark:rf-border-zinc-800 dark:rf-bg-zinc-950",
1541
+ className
1542
+ ),
1543
+ ...props
1544
+ }
1545
+ )
1546
+ ] }));
1547
+ AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
1548
+ var AlertDialogHeader = ({
1549
+ className,
1550
+ ...props
1551
+ }) => /* @__PURE__ */ jsx17(
1552
+ "div",
1553
+ {
1554
+ className: cn(
1555
+ "rf-flex rf-flex-col rf-space-y-2 rf-text-center sm:rf-text-left",
1556
+ className
1557
+ ),
1558
+ ...props
1559
+ }
1560
+ );
1561
+ AlertDialogHeader.displayName = "AlertDialogHeader";
1562
+ var AlertDialogFooter = ({
1563
+ className,
1564
+ ...props
1565
+ }) => /* @__PURE__ */ jsx17(
1566
+ "div",
1567
+ {
1568
+ className: cn(
1569
+ "rf-flex rf-flex-col-reverse sm:rf-flex-row sm:rf-justify-end sm:rf-space-x-2",
1570
+ className
1571
+ ),
1572
+ ...props
1573
+ }
1574
+ );
1575
+ AlertDialogFooter.displayName = "AlertDialogFooter";
1576
+ var AlertDialogTitle = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx17(
1577
+ AlertDialogPrimitive.Title,
1578
+ {
1579
+ ref,
1580
+ className: cn("rf-text-lg rf-font-semibold", className),
1581
+ ...props
1582
+ }
1583
+ ));
1584
+ AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
1585
+ var AlertDialogDescription = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx17(
1586
+ AlertDialogPrimitive.Description,
1587
+ {
1588
+ ref,
1589
+ className: cn(
1590
+ "rf-text-sm rf-text-zinc-500 dark:rf-text-zinc-400",
1591
+ className
1592
+ ),
1593
+ ...props
1594
+ }
1595
+ ));
1596
+ AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
1597
+ var AlertDialogAction = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx17(
1598
+ AlertDialogPrimitive.Action,
1599
+ {
1600
+ ref,
1601
+ className: cn(buttonVariants(), className),
1602
+ ...props
1603
+ }
1604
+ ));
1605
+ AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
1606
+ var AlertDialogCancel = React6.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx17(
1607
+ AlertDialogPrimitive.Cancel,
1608
+ {
1609
+ ref,
1610
+ className: cn(
1611
+ buttonVariants({ variant: "outline" }),
1612
+ "rf-mt-2 sm:rf-mt-0",
1613
+ className
1614
+ ),
1615
+ ...props
1616
+ }
1617
+ ));
1618
+ AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
1619
+
1620
+ // lib/components/OrderDialog/OrderDialog.tsx
1621
+ import { useState as useState7 } from "react";
1622
+ import { QueryClient, QueryClientProvider } from "react-query";
1623
+
1624
+ // lib/components/OrderDialog/CheckoutOrder.tsx
1625
+ import { MapPin } from "lucide-react";
1626
+
1627
+ // lib/components/ui/input.tsx
1628
+ import * as React7 from "react";
1629
+ import { jsx as jsx18 } from "react/jsx-runtime";
1630
+ var Input = React7.forwardRef(
1631
+ ({ className, type, ...props }, ref) => {
1632
+ return /* @__PURE__ */ jsx18(
1633
+ "input",
1634
+ {
1635
+ type,
1636
+ className: cn(
1637
+ "rf-flex rf-h-9 rf-w-full rf-rounded-md rf-border rf-border-zinc-200 rf-bg-white rf-px-3 rf-py-1 rf-text-sm rf-shadow-sm rf-transition-colors file:rf-border-0 file:rf-bg-transparent file:rf-text-sm file:rf-font-medium placeholder:rf-text-zinc-500 focus-visible:rf-outline-none focus-visible:rf-ring-1 focus-visible:rf-ring-zinc-950 disabled:rf-cursor-not-allowed disabled:rf-opacity-50 dark:rf-border-zinc-800 dark:rf-bg-zinc-950 dark:rf-placeholder-zinc-400 dark:focus-visible:rf-ring-zinc-300",
1638
+ className
1639
+ ),
1640
+ ref,
1641
+ ...props
1642
+ }
1643
+ );
1644
+ }
1645
+ );
1646
+ Input.displayName = "Input";
1647
+
1648
+ // lib/components/OrderDialog/CheckoutOrder.tsx
1649
+ import { useState as useState5 } from "react";
1650
+ import { toast } from "react-hot-toast";
1651
+ import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
1652
+ var CheckoutOrder = ({
1653
+ finalCost,
1654
+ onConfirmCheckout,
1655
+ onCancel
1656
+ }) => {
1657
+ const [selectedAddressId, setSelectedAddressId] = useState5(
1658
+ null
1659
+ );
1660
+ const [savedAddresses] = useState5([
1661
+ {
1662
+ id: 1,
1663
+ name: "Home",
1664
+ street: "123 Main St",
1665
+ city: "San Francisco",
1666
+ state: "CA",
1667
+ zipCode: "94105",
1668
+ country: "USA",
1669
+ isDefault: true
1670
+ },
1671
+ {
1672
+ id: 2,
1673
+ name: "Office",
1674
+ street: "456 Market St",
1675
+ city: "San Francisco",
1676
+ state: "CA",
1677
+ zipCode: "94103",
1678
+ country: "USA",
1679
+ isDefault: false
1680
+ }
1681
+ ]);
1682
+ const [addressForm, setAddressForm] = useState5({
1683
+ name: "",
1684
+ street: "",
1685
+ city: "",
1686
+ state: "",
1687
+ zipCode: "",
1688
+ country: ""
1689
+ });
1690
+ const handleInputChange = (e) => {
1691
+ const { name, value } = e.target;
1692
+ setAddressForm((prev) => ({
1693
+ ...prev,
1694
+ [name]: value
1695
+ }));
1696
+ };
1697
+ const handleSelectAddress = (addressId) => {
1698
+ setSelectedAddressId(addressId);
1699
+ const selectedAddress = savedAddresses.find((addr) => addr.id === addressId);
1700
+ if (selectedAddress) {
1701
+ setAddressForm({
1702
+ name: selectedAddress.name,
1703
+ street: selectedAddress.street,
1704
+ city: selectedAddress.city,
1705
+ state: selectedAddress.state,
1706
+ zipCode: selectedAddress.zipCode,
1707
+ country: selectedAddress.country
1708
+ });
1709
+ }
1710
+ };
1711
+ const handleConfirmCheckout = () => {
1712
+ if (!selectedAddressId && (!addressForm.street || !addressForm.city || !addressForm.zipCode)) {
1713
+ toast.error("Please provide a complete shipping address.");
1714
+ return;
1715
+ }
1716
+ toast.success("Your PCB order has been placed successfully.");
1717
+ onConfirmCheckout();
1718
+ };
1719
+ return /* @__PURE__ */ jsxs14("div", { className: "rf-bg-white rf-rounded-xl rf-p-6 rf-mx-auto", children: [
1720
+ /* @__PURE__ */ jsx19("h2", { className: "rf-text-2xl rf-font-bold rf-mb-6", children: "Checkout" }),
1721
+ /* @__PURE__ */ jsxs14("div", { className: "rf-grid rf-grid-cols-1 md:rf-grid-cols-2 rf-gap-8", children: [
1722
+ /* @__PURE__ */ jsxs14("div", { className: "rf-space-y-6", children: [
1723
+ /* @__PURE__ */ jsx19("h3", { className: "rf-text-lg rf-font-semibold", children: "Shipping Address" }),
1724
+ savedAddresses.length > 0 && /* @__PURE__ */ jsxs14("div", { className: "rf-space-y-4", children: [
1725
+ /* @__PURE__ */ jsx19("div", { className: "rf-text-sm rf-font-medium rf-text-gray-500", children: "Saved Addresses" }),
1726
+ /* @__PURE__ */ jsx19("div", { className: "rf-flex rf-flex-wrap rf-gap-3", children: savedAddresses.map((address) => /* @__PURE__ */ jsxs14(
1727
+ "button",
1728
+ {
1729
+ type: "button",
1730
+ onClick: () => handleSelectAddress(address.id),
1731
+ className: cn(
1732
+ "rf-flex rf-items-center rf-gap-2 rf-px-3 rf-py-2 rf-text-sm rf-rounded-md rf-border rf-transition-colors",
1733
+ selectedAddressId === address.id ? "rf-border-blue-500 rf-bg-blue-50 rf-text-blue-700" : "rf-border-gray-200 rf-hover:bg-gray-50"
1734
+ ),
1735
+ children: [
1736
+ /* @__PURE__ */ jsx19(MapPin, { className: "rf-h-4 rf-w-4" }),
1737
+ /* @__PURE__ */ jsx19("span", { children: address.name }),
1738
+ address.isDefault && /* @__PURE__ */ jsx19("span", { className: "rf-inline-flex rf-items-center rf-rounded-full rf-bg-blue-100 rf-px-2 rf-py-0.5 rf-text-xs rf-font-medium rf-text-blue-800", children: "Default" })
1739
+ ]
1740
+ },
1741
+ address.id
1742
+ )) })
1743
+ ] }),
1744
+ /* @__PURE__ */ jsxs14("div", { className: "rf-space-y-4", children: [
1745
+ /* @__PURE__ */ jsx19("div", { className: "rf-grid rf-grid-cols-2 rf-gap-4", children: /* @__PURE__ */ jsxs14("div", { className: "rf-space-y-2", children: [
1746
+ /* @__PURE__ */ jsx19("label", { htmlFor: "name", children: "Address Name" }),
1747
+ /* @__PURE__ */ jsx19(
1748
+ Input,
1749
+ {
1750
+ id: "name",
1751
+ name: "name",
1752
+ placeholder: "Home, Office, etc.",
1753
+ value: addressForm.name,
1754
+ onChange: handleInputChange
1755
+ }
1756
+ )
1757
+ ] }) }),
1758
+ /* @__PURE__ */ jsxs14("div", { className: "rf-space-y-2", children: [
1759
+ /* @__PURE__ */ jsx19("label", { htmlFor: "street", children: "Street Address" }),
1760
+ /* @__PURE__ */ jsx19(
1761
+ Input,
1762
+ {
1763
+ id: "street",
1764
+ name: "street",
1765
+ placeholder: "123 Main St",
1766
+ value: addressForm.street,
1767
+ onChange: handleInputChange
1768
+ }
1769
+ )
1770
+ ] }),
1771
+ /* @__PURE__ */ jsxs14("div", { className: "rf-grid rf-grid-cols-2 rf-gap-4", children: [
1772
+ /* @__PURE__ */ jsxs14("div", { className: "rf-space-y-2", children: [
1773
+ /* @__PURE__ */ jsx19("label", { htmlFor: "city", children: "City" }),
1774
+ /* @__PURE__ */ jsx19(
1775
+ Input,
1776
+ {
1777
+ id: "city",
1778
+ name: "city",
1779
+ placeholder: "City",
1780
+ value: addressForm.city,
1781
+ onChange: handleInputChange
1782
+ }
1783
+ )
1784
+ ] }),
1785
+ /* @__PURE__ */ jsxs14("div", { className: "rf-space-y-2", children: [
1786
+ /* @__PURE__ */ jsx19("label", { htmlFor: "state", children: "State" }),
1787
+ /* @__PURE__ */ jsx19(
1788
+ Input,
1789
+ {
1790
+ id: "state",
1791
+ name: "state",
1792
+ placeholder: "State",
1793
+ value: addressForm.state,
1794
+ onChange: handleInputChange
1795
+ }
1796
+ )
1797
+ ] })
1798
+ ] }),
1799
+ /* @__PURE__ */ jsxs14("div", { className: "rf-grid rf-grid-cols-2 rf-gap-4", children: [
1800
+ /* @__PURE__ */ jsxs14("div", { className: "rf-space-y-2", children: [
1801
+ /* @__PURE__ */ jsx19("label", { htmlFor: "zipCode", children: "Zip Code" }),
1802
+ /* @__PURE__ */ jsx19(
1803
+ Input,
1804
+ {
1805
+ id: "zipCode",
1806
+ name: "zipCode",
1807
+ placeholder: "Zip Code",
1808
+ value: addressForm.zipCode,
1809
+ onChange: handleInputChange
1810
+ }
1811
+ )
1812
+ ] }),
1813
+ /* @__PURE__ */ jsxs14("div", { className: "rf-space-y-2", children: [
1814
+ /* @__PURE__ */ jsx19("label", { htmlFor: "country", children: "Country" }),
1815
+ /* @__PURE__ */ jsx19(
1816
+ Input,
1817
+ {
1818
+ id: "country",
1819
+ name: "country",
1820
+ placeholder: "Country",
1821
+ value: addressForm.country,
1822
+ onChange: handleInputChange
1823
+ }
1824
+ )
1825
+ ] })
1826
+ ] })
1827
+ ] })
1828
+ ] }),
1829
+ /* @__PURE__ */ jsxs14("div", { className: "rf-bg-gray-50 rf-p-6 rf-rounded-lg", children: [
1830
+ /* @__PURE__ */ jsx19("h3", { className: "rf-text-lg rf-font-semibold rf-mb-4", children: "Order Summary" }),
1831
+ /* @__PURE__ */ jsxs14("div", { className: "rf-space-y-4", children: [
1832
+ /* @__PURE__ */ jsxs14("div", { className: "rf-flex rf-justify-between rf-py-2 rf-border-b rf-border-gray-200", children: [
1833
+ /* @__PURE__ */ jsx19("span", { className: "rf-text-gray-600", children: "PCB Manufacturing" }),
1834
+ /* @__PURE__ */ jsxs14("span", { className: "rf-font-medium", children: [
1835
+ "$",
1836
+ (finalCost * 0.6).toFixed(2)
1837
+ ] })
1838
+ ] }),
1839
+ /* @__PURE__ */ jsxs14("div", { className: "rf-flex rf-justify-between rf-py-2 rf-border-b rf-border-gray-200", children: [
1840
+ /* @__PURE__ */ jsx19("span", { className: "rf-text-gray-600", children: "Components" }),
1841
+ /* @__PURE__ */ jsxs14("span", { className: "rf-font-medium", children: [
1842
+ "$",
1843
+ (finalCost * 0.3).toFixed(2)
1844
+ ] })
1845
+ ] }),
1846
+ /* @__PURE__ */ jsxs14("div", { className: "rf-flex rf-justify-between rf-py-2 rf-border-b rf-border-gray-200", children: [
1847
+ /* @__PURE__ */ jsx19("span", { className: "rf-text-gray-600", children: "Assembly" }),
1848
+ /* @__PURE__ */ jsxs14("span", { className: "rf-font-medium", children: [
1849
+ "$",
1850
+ (finalCost * 0.1).toFixed(2)
1851
+ ] })
1852
+ ] }),
1853
+ /* @__PURE__ */ jsxs14("div", { className: "rf-flex rf-justify-between rf-py-2 rf-border-b rf-border-gray-200", children: [
1854
+ /* @__PURE__ */ jsx19("span", { className: "rf-text-gray-600", children: "Shipping" }),
1855
+ /* @__PURE__ */ jsx19("span", { className: "rf-font-medium", children: "$15.00" })
1856
+ ] }),
1857
+ /* @__PURE__ */ jsxs14("div", { className: "rf-flex rf-justify-between rf-py-2 rf-text-lg rf-font-bold", children: [
1858
+ /* @__PURE__ */ jsx19("span", { children: "Total" }),
1859
+ /* @__PURE__ */ jsxs14("span", { children: [
1860
+ "$",
1861
+ (finalCost + 15).toFixed(2)
1862
+ ] })
1863
+ ] }),
1864
+ /* @__PURE__ */ jsxs14("div", { className: "rf-pt-4", children: [
1865
+ /* @__PURE__ */ jsx19(
1866
+ Button,
1867
+ {
1868
+ onClick: handleConfirmCheckout,
1869
+ className: "rf-w-full rf-bg-gray-700 rf-hover:bg-gray-800 rf-text-white rf-py-3",
1870
+ children: "Confirm and Place Order"
1871
+ }
1872
+ ),
1873
+ /* @__PURE__ */ jsx19(
1874
+ Button,
1875
+ {
1876
+ variant: "outline",
1877
+ onClick: onCancel,
1878
+ className: "rf-w-full rf-mt-3",
1879
+ children: "Cancel"
1880
+ }
1881
+ )
1882
+ ] })
1883
+ ] })
1884
+ ] })
1885
+ ] })
1886
+ ] });
1887
+ };
1888
+
1889
+ // lib/components/OrderDialog/InitialOrder.tsx
1890
+ import "ky";
1891
+
1892
+ // lib/components/ui/select.tsx
1893
+ import * as SelectPrimitive from "@radix-ui/react-select";
1894
+ import { Check as Check2, ChevronDown, ChevronUp } from "lucide-react";
1895
+ import * as React8 from "react";
1896
+ import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
1897
+ var Select = SelectPrimitive.Root;
1898
+ var SelectValue = SelectPrimitive.Value;
1899
+ var SelectTrigger = React8.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs15(
1900
+ SelectPrimitive.Trigger,
1901
+ {
1902
+ ref,
1903
+ className: cn(
1904
+ "rf-flex rf-h-10 rf-w-full rf-items-center rf-justify-between rf-rounded-md rf-border rf-border-input rf-bg-background rf-px-3 rf-py-2 rf-text-sm rf-ring-offset-background rf-placeholder:text-muted-foreground focus:rf-outline-none focus:rf-ring-2 focus:rf-ring-ring focus:rf-ring-offset-2 disabled:rf-cursor-not-allowed disabled:rf-opacity-50 [&>span]:rf-line-clamp-1",
1905
+ className
1906
+ ),
1907
+ ...props,
1908
+ children: [
1909
+ children,
1910
+ /* @__PURE__ */ jsx20(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ jsx20(ChevronDown, { className: "rf-h-4 rf-w-4 rf-opacity-50" }) })
1911
+ ]
1912
+ }
1913
+ ));
1914
+ SelectTrigger.displayName = SelectPrimitive.Trigger.displayName;
1915
+ var SelectScrollUpButton = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
1916
+ SelectPrimitive.ScrollUpButton,
1917
+ {
1918
+ ref,
1919
+ className: cn(
1920
+ "rf-flex rf-cursor-default rf-items-center rf-justify-center rf-py-1",
1921
+ className
1922
+ ),
1923
+ ...props,
1924
+ children: /* @__PURE__ */ jsx20(ChevronUp, { className: "rf-h-4 rf-w-4" })
1925
+ }
1926
+ ));
1927
+ SelectScrollUpButton.displayName = SelectPrimitive.ScrollUpButton.displayName;
1928
+ var SelectScrollDownButton = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
1929
+ SelectPrimitive.ScrollDownButton,
1930
+ {
1931
+ ref,
1932
+ className: cn(
1933
+ "rf-flex rf-cursor-default rf-items-center rf-justify-center rf-py-1",
1934
+ className
1935
+ ),
1936
+ ...props,
1937
+ children: /* @__PURE__ */ jsx20(ChevronDown, { className: "rf-h-4 rf-w-4" })
1938
+ }
1939
+ ));
1940
+ SelectScrollDownButton.displayName = SelectPrimitive.ScrollDownButton.displayName;
1941
+ var SelectContent = React8.forwardRef(({ className, children, position = "popper", ...props }, ref) => /* @__PURE__ */ jsx20(SelectPrimitive.Portal, { children: /* @__PURE__ */ jsxs15(
1942
+ SelectPrimitive.Content,
1943
+ {
1944
+ ref,
1945
+ className: cn(
1946
+ "rf-relative rf-z-[100] rf-max-h-96 rf-min-w-[8rem] rf-overflow-hidden rf-rounded-md rf-border rf-bg-white rf-text-black rf-shadow-md data-[state=open]:rf-animate-in data-[state=closed]:rf-animate-out data-[state=closed]:rf-fade-out-0 data-[state=open]:rf-fade-in-0 data-[state=closed]:rf-zoom-out-95 data-[state=open]:rf-zoom-in-95 data-[side=bottom]:rf-slide-in-from-top-2 data-[side=left]:rf-slide-in-from-right-2 data-[side=right]:rf-slide-in-from-left-2 data-[side=top]:rf-slide-in-from-bottom-2",
1947
+ position === "popper" && "data-[side=bottom]:rf-translate-y-1 data-[side=left]:-rf-translate-x-1 data-[side=right]:rf-translate-x-1 data-[side=top]:-rf-translate-y-1",
1948
+ className
1949
+ ),
1950
+ position,
1951
+ ...props,
1952
+ children: [
1953
+ /* @__PURE__ */ jsx20(SelectScrollUpButton, {}),
1954
+ /* @__PURE__ */ jsx20(
1955
+ SelectPrimitive.Viewport,
1956
+ {
1957
+ className: cn(
1958
+ "rf-p-1",
1959
+ position === "popper" && "rf-h-[var(--radix-select-trigger-height)] rf-w-full rf-min-w-[var(--radix-select-trigger-width)]"
1960
+ ),
1961
+ children
1962
+ }
1963
+ ),
1964
+ /* @__PURE__ */ jsx20(SelectScrollDownButton, {})
1965
+ ]
1966
+ }
1967
+ ) }));
1968
+ SelectContent.displayName = SelectPrimitive.Content.displayName;
1969
+ var SelectLabel = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
1970
+ SelectPrimitive.Label,
1971
+ {
1972
+ ref,
1973
+ className: cn(
1974
+ "rf-py-1.5 rf-pl-8 rf-pr-2 rf-text-sm rf-font-semibold",
1975
+ className
1976
+ ),
1977
+ ...props
1978
+ }
1979
+ ));
1980
+ SelectLabel.displayName = SelectPrimitive.Label.displayName;
1981
+ var SelectItem = React8.forwardRef(({ className, children, ...props }, ref) => /* @__PURE__ */ jsxs15(
1982
+ SelectPrimitive.Item,
1983
+ {
1984
+ ref,
1985
+ className: cn(
1986
+ "rf-relative rf-flex rf-w-full rf-cursor-default rf-select-none rf-items-center rf-rounded-sm rf-py-1.5 rf-pl-8 rf-pr-2 rf-text-sm rf-text-gray-800 rf-outline-none focus:rf-bg-gray-100 focus:rf-text-gray-900 data-[disabled]:rf-pointer-events-none data-[disabled]:rf-opacity-50",
1987
+ className
1988
+ ),
1989
+ ...props,
1990
+ children: [
1991
+ /* @__PURE__ */ jsx20("span", { className: "rf-absolute rf-left-2 rf-flex rf-h-3.5 rf-w-3.5 rf-items-center rf-justify-center", children: /* @__PURE__ */ jsx20(SelectPrimitive.ItemIndicator, { children: /* @__PURE__ */ jsx20(Check2, { className: "rf-h-4 rf-w-4" }) }) }),
1992
+ /* @__PURE__ */ jsx20(SelectPrimitive.ItemText, { children })
1993
+ ]
1994
+ }
1995
+ ));
1996
+ SelectItem.displayName = SelectPrimitive.Item.displayName;
1997
+ var SelectSeparator = React8.forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx20(
1998
+ SelectPrimitive.Separator,
1999
+ {
2000
+ ref,
2001
+ className: cn("-rf-mx-1 rf-my-1 rf-h-px rf-bg-muted", className),
2002
+ ...props
2003
+ }
2004
+ ));
2005
+ SelectSeparator.displayName = SelectPrimitive.Separator.displayName;
2006
+
2007
+ // lib/components/ui/skeleton.tsx
2008
+ import { jsx as jsx21 } from "react/jsx-runtime";
2009
+ function Skeleton({
2010
+ className,
2011
+ ...props
2012
+ }) {
2013
+ return /* @__PURE__ */ jsx21(
2014
+ "div",
2015
+ {
2016
+ className: cn("rf-animate-pulse rf-rounded-md rf-bg-muted", className),
2017
+ ...props
2018
+ }
2019
+ );
2020
+ }
2021
+
2022
+ // lib/utils/get-registry-ky.ts
2023
+ import ky from "ky";
2024
+ function getRegistryKy() {
2025
+ const useRegistryPrefix = typeof window !== "undefined" && window.__RUNFRAME_REGISTRY_BASE_URL__ === true;
2026
+ const registryApiBaseUrl = useRegistryPrefix ? "/registry" : "https://registry-api.tscircuit.com";
2027
+ return ky.create({
2028
+ prefixUrl: registryApiBaseUrl,
2029
+ timeout: 3e4
2030
+ });
2031
+ }
2032
+ var registryKy = {
2033
+ get: (url, options) => getRegistryKy().get(url, options),
2034
+ post: (url, options) => getRegistryKy().post(url, options),
2035
+ put: (url, options) => getRegistryKy().put(url, options),
2036
+ delete: (url, options) => getRegistryKy().delete(url, options),
2037
+ patch: (url, options) => getRegistryKy().patch(url, options)
2038
+ };
2039
+
2040
+ // lib/components/OrderDialog/InitialOrder.tsx
2041
+ import { ArrowDown } from "lucide-react";
2042
+ import { useEffect as useEffect3, useState as useState6 } from "react";
2043
+ import { jsx as jsx22, jsxs as jsxs16 } from "react/jsx-runtime";
2044
+ var InitialOrderScreen = ({
2045
+ onCancel,
2046
+ onContinue
2047
+ }) => {
2048
+ const productCategories = [
2049
+ { id: "prototype", name: "Prototype" },
2050
+ { id: "development", name: "Development board" }
2051
+ ];
2052
+ const [isLoading, setIsLoading] = useState6(false);
2053
+ const [estimatedCost, setEstimatedCost] = useState6(null);
2054
+ const [selectedCategory, setSelectedCategory] = useState6("prototype");
2055
+ useEffect3(() => {
2056
+ handleGetEstimate();
2057
+ }, []);
2058
+ const handleSelectCategory = (category) => {
2059
+ setSelectedCategory(category);
2060
+ setEstimatedCost(null);
2061
+ setTimeout(() => {
2062
+ handleGetEstimate();
2063
+ }, 0);
2064
+ };
2065
+ const createOrderQuote = async () => {
2066
+ const { order_quote_id } = await registryKy.post("order_quotes/create", {
2067
+ json: {
2068
+ package_release_id: "",
2069
+ vendor_name: ""
2070
+ }
2071
+ }).json();
2072
+ return order_quote_id;
2073
+ };
2074
+ const getOrderQuote = async (order_quote_id) => {
2075
+ const { order_quote } = await registryKy.post(`order_quotes/get`, {
2076
+ json: {
2077
+ order_quote_id
2078
+ }
2079
+ }).json();
2080
+ return order_quote;
2081
+ };
2082
+ const pollOrderQuote = async (quoteId, maxAttempts = 30) => {
2083
+ let attempts = 0;
2084
+ while (attempts < maxAttempts) {
2085
+ try {
2086
+ const orderQuote = await getOrderQuote(quoteId);
2087
+ if (orderQuote.is_complete) {
2088
+ setEstimatedCost(orderQuote.total_cost);
2089
+ setIsLoading(false);
2090
+ return orderQuote;
2091
+ }
2092
+ if (orderQuote.has_error) {
2093
+ throw new Error(orderQuote.error);
2094
+ }
2095
+ attempts++;
2096
+ await new Promise((resolve) => setTimeout(resolve, 2e3));
2097
+ } catch (error) {
2098
+ console.error("Error polling order quote:", error);
2099
+ setIsLoading(false);
2100
+ }
2101
+ }
2102
+ setIsLoading(false);
2103
+ throw new Error("Polling timed out after maximum attempts");
2104
+ };
2105
+ const handleGetEstimate = async () => {
2106
+ if (!selectedCategory) return;
2107
+ const order_quote_id = await createOrderQuote();
2108
+ if (!order_quote_id) {
2109
+ console.error("Error creating order quote");
2110
+ setEstimatedCost(null);
2111
+ return;
2112
+ }
2113
+ setIsLoading(true);
2114
+ setEstimatedCost(null);
2115
+ try {
2116
+ const orderQuote = await pollOrderQuote(order_quote_id);
2117
+ setEstimatedCost(orderQuote.total_cost);
2118
+ } catch (error) {
2119
+ console.error("Error getting estimate:", error);
2120
+ setEstimatedCost(null);
2121
+ }
2122
+ };
2123
+ return /* @__PURE__ */ jsxs16("div", { className: "rf-flex rf-flex-col rf-bg-white rf-rounded-xl rf-p-8 rf-max-w-md rf-w-full rf-mx-auto", children: [
2124
+ /* @__PURE__ */ jsx22("h2", { className: "rf-text-3xl rf-font-bold rf-text-center rf-mb-8", children: "Order PCB" }),
2125
+ /* @__PURE__ */ jsxs16("div", { className: "rf-mb-8", children: [
2126
+ /* @__PURE__ */ jsx22(
2127
+ "label",
2128
+ {
2129
+ htmlFor: "category",
2130
+ className: "rf-block rf-text-sm rf-font-medium rf-text-gray-700 rf-mb-2",
2131
+ children: "Select Product Category"
2132
+ }
2133
+ ),
2134
+ /* @__PURE__ */ jsxs16(
2135
+ Select,
2136
+ {
2137
+ onValueChange: handleSelectCategory,
2138
+ value: selectedCategory || void 0,
2139
+ children: [
2140
+ /* @__PURE__ */ jsx22(SelectTrigger, { className: "rf-w-full", children: /* @__PURE__ */ jsx22(SelectValue, { placeholder: "Select a category" }) }),
2141
+ /* @__PURE__ */ jsx22(SelectContent, { children: productCategories.map((category) => /* @__PURE__ */ jsx22(SelectItem, { value: category.id, children: category.name }, category.id)) })
2142
+ ]
2143
+ }
2144
+ )
2145
+ ] }),
2146
+ isLoading ? /* @__PURE__ */ jsxs16("div", { className: "rf-flex rf-flex-col rf-items-center rf-mb-8", children: [
2147
+ /* @__PURE__ */ jsxs16("div", { className: "rf-animate-pulse rf-flex rf-space-x-2 rf-items-center rf-mb-3", children: [
2148
+ /* @__PURE__ */ jsx22(ArrowDown, { className: "rf-h-5 rf-w-5 rf-text-gray-400" }),
2149
+ /* @__PURE__ */ jsx22("span", { className: "rf-text-gray-500", children: "Fetching estimate..." })
2150
+ ] }),
2151
+ /* @__PURE__ */ jsx22(Skeleton, { className: "rf-h-6 rf-w-3/4 rf-mb-2" }),
2152
+ /* @__PURE__ */ jsx22(Skeleton, { className: "rf-h-6 rf-w-1/2" })
2153
+ ] }) : estimatedCost !== null ? /* @__PURE__ */ jsxs16("div", { className: "rf-bg-gray-50 rf-p-4 rf-rounded-lg rf-mb-8", children: [
2154
+ /* @__PURE__ */ jsx22("p", { className: "rf-text-sm rf-text-gray-600 rf-mb-2", children: "Estimated Cost:" }),
2155
+ /* @__PURE__ */ jsxs16("p", { className: "rf-text-2xl rf-font-bold rf-text-gray-900", children: [
2156
+ "$",
2157
+ estimatedCost.toFixed(2)
2158
+ ] }),
2159
+ /* @__PURE__ */ jsx22("p", { className: "rf-text-xs rf-text-gray-500 rf-mt-1", children: "Pricing may vary based on specifications" })
2160
+ ] }) : null,
2161
+ /* @__PURE__ */ jsxs16("div", { className: "rf-flex rf-justify-between rf-mt-auto", children: [
2162
+ /* @__PURE__ */ jsx22(
2163
+ Button,
2164
+ {
2165
+ variant: "outline",
2166
+ onClick: onCancel,
2167
+ className: "rf-px-8 rf-border-red-500 rf-text-red-500 hover:rf-bg-red-50 hover:rf-text-red-600",
2168
+ children: "Cancel"
2169
+ }
2170
+ ),
2171
+ /* @__PURE__ */ jsx22(
2172
+ Button,
2173
+ {
2174
+ onClick: estimatedCost !== null ? onContinue : handleGetEstimate,
2175
+ className: estimatedCost !== null ? "rf-px-8 rf-bg-gray-700 hover:rf-bg-gray-800" : "rf-px-8 rf-bg-blue-600 hover:rf-bg-blue-700",
2176
+ children: estimatedCost !== null ? "Continue" : "Get Estimate"
2177
+ }
2178
+ )
2179
+ ] })
2180
+ ] });
2181
+ };
2182
+
2183
+ // lib/components/OrderDialog/StepwiseProgress.tsx
2184
+ import ky3 from "ky";
2185
+
2186
+ // lib/components/ui/progress.tsx
2187
+ import * as React9 from "react";
2188
+ import * as ProgressPrimitive from "@radix-ui/react-progress";
2189
+ import { jsx as jsx23 } from "react/jsx-runtime";
2190
+ var Progress = React9.forwardRef(({ className, value, ...props }, ref) => /* @__PURE__ */ jsx23(
2191
+ ProgressPrimitive.Root,
2192
+ {
2193
+ ref,
2194
+ className: cn(
2195
+ "rf-relative rf-h-2 rf-w-full rf-overflow-hidden rf-rounded-full rf-bg-zinc-100 dark:rf-bg-zinc-800",
2196
+ className
2197
+ ),
2198
+ ...props,
2199
+ children: /* @__PURE__ */ jsx23(
2200
+ ProgressPrimitive.Indicator,
2201
+ {
2202
+ className: "rf-h-full rf-w-full rf-flex-1 rf-bg-zinc-900 rf-transition-all dark:rf-bg-zinc-50",
2203
+ style: { transform: `translateX(-${100 - (value || 0)}%)` }
2204
+ }
2205
+ )
2206
+ }
2207
+ ));
2208
+ Progress.displayName = "Progress";
2209
+
2210
+ // lib/components/OrderDialog/StepwiseProgress.tsx
2211
+ import { ArrowDown as ArrowDown2, Check as Check3, Loader2 as Loader22 } from "lucide-react";
2212
+ import { useQuery } from "react-query";
2213
+
2214
+ // lib/utils/order-steps.ts
2215
+ var orderSteps = [
2216
+ { order_step_id: 1, key: "are_gerbers_generated", title: "Generate Gerbers" },
2217
+ { order_step_id: 2, key: "are_gerbers_uploaded", title: "Upload Gerbers" },
2218
+ { order_step_id: 3, key: "is_gerber_analyzed", title: "Analyze Gerber" },
2219
+ {
2220
+ order_step_id: 4,
2221
+ key: "are_initial_costs_calculated",
2222
+ title: "Calculate Initial Costs"
2223
+ },
2224
+ { order_step_id: 5, key: "is_pcb_added_to_cart", title: "Add PCB to Cart" },
2225
+ { order_step_id: 6, key: "is_bom_uploaded", title: "Upload BOM" },
2226
+ { order_step_id: 7, key: "is_pnp_uploaded", title: "Upload PnP" },
2227
+ { order_step_id: 8, key: "is_bom_pnp_analyzed", title: "Analyze BOM & PnP" },
2228
+ {
2229
+ order_step_id: 9,
2230
+ key: "is_bom_parsing_complete",
2231
+ title: "BOM Parsing Complete"
2232
+ },
2233
+ {
2234
+ order_step_id: 10,
2235
+ key: "are_components_available",
2236
+ title: "Components Available"
2237
+ },
2238
+ {
2239
+ order_step_id: 11,
2240
+ key: "is_patch_map_generated",
2241
+ title: "Generate Patch Map"
2242
+ },
2243
+ {
2244
+ order_step_id: 12,
2245
+ key: "is_json_merge_file_created",
2246
+ title: "Create JSON Merge File"
2247
+ },
2248
+ {
2249
+ order_step_id: 13,
2250
+ key: "is_dfm_result_generated",
2251
+ title: "Generate DFM Result"
2252
+ },
2253
+ { order_step_id: 14, key: "are_files_downloaded", title: "Download Files" },
2254
+ {
2255
+ order_step_id: 15,
2256
+ key: "are_product_categories_fetched",
2257
+ title: "Fetch Product Categories"
2258
+ },
2259
+ {
2260
+ order_step_id: 16,
2261
+ key: "are_final_costs_calculated",
2262
+ title: "Calculate Final Costs"
2263
+ },
2264
+ {
2265
+ order_step_id: 17,
2266
+ key: "is_json_merge_file_updated",
2267
+ title: "Update JSON Merge File"
2268
+ },
2269
+ { order_step_id: 18, key: "is_added_to_cart", title: "Add to Cart" }
2270
+ ].map((step, index) => ({
2271
+ ...step,
2272
+ completed: false,
2273
+ active: index === 0
2274
+ // First step starts as active
2275
+ }));
2276
+
2277
+ // lib/components/OrderDialog/StepwiseProgress.tsx
2278
+ import { jsx as jsx24, jsxs as jsxs17 } from "react/jsx-runtime";
2279
+ var StepwiseProgressPanel = ({
2280
+ orderId,
2281
+ title = "Order PCB",
2282
+ onCancel,
2283
+ loading: externalLoading = false,
2284
+ setStage
2285
+ }) => {
2286
+ const { data, isLoading } = useQuery({
2287
+ queryKey: ["orderState", orderId],
2288
+ queryFn: async () => {
2289
+ const response = await ky3.get("registry/orders/get", {
2290
+ searchParams: { order_id: orderId },
2291
+ headers: {
2292
+ Authorization: `Bearer account-1234`
2293
+ }
2294
+ }).json();
2295
+ if (response.orderState.current_step === "is_added_to_cart") {
2296
+ setStage("checkout");
2297
+ }
2298
+ return response;
2299
+ },
2300
+ refetchInterval: 2e3,
2301
+ refetchIntervalInBackground: true
2302
+ });
2303
+ const steps = orderSteps.map((step) => {
2304
+ if (!data?.orderState) return step;
2305
+ const currentStepIndex = orderSteps.findIndex(
2306
+ (orderStep) => orderStep.key === data.orderState.current_step
2307
+ );
2308
+ const stepIndex = orderSteps.findIndex(
2309
+ (orderStep) => orderStep.key === step.key
2310
+ );
2311
+ return {
2312
+ ...step,
2313
+ completed: stepIndex < currentStepIndex,
2314
+ active: stepIndex === currentStepIndex
2315
+ };
2316
+ });
2317
+ const completedSteps = steps.filter((step) => step.completed);
2318
+ const activeStep = steps.find((step) => step.active);
2319
+ const lastCompletedStep = completedSteps[completedSteps.length - 1];
2320
+ const totalSteps = steps.length;
2321
+ const progress = Math.round(completedSteps.length / totalSteps * 100);
2322
+ const loading = isLoading || externalLoading;
2323
+ return /* @__PURE__ */ jsxs17("div", { className: "rf-flex rf-flex-col rf-bg-white rf-rounded-xl rf-p-6 rf-max-w-xl rf-w-full rf-mx-auto", children: [
2324
+ /* @__PURE__ */ jsxs17("div", { className: "rf-flex rf-items-center rf-justify-between rf-mb-6", children: [
2325
+ /* @__PURE__ */ jsx24("h2", { className: "rf-text-2xl rf-font-bold", children: title }),
2326
+ /* @__PURE__ */ jsxs17("div", { className: "rf-text-sm rf-text-muted-foreground", children: [
2327
+ completedSteps.length,
2328
+ " of ",
2329
+ totalSteps,
2330
+ " completed"
2331
+ ] })
2332
+ ] }),
2333
+ /* @__PURE__ */ jsx24(Progress, { value: progress, className: "rf-h-2 rf-mb-8" }),
2334
+ /* @__PURE__ */ jsxs17("div", { className: "rf-space-y-6 rf-mb-8", children: [
2335
+ lastCompletedStep && /* @__PURE__ */ jsxs17("div", { className: "rf-flex rf-items-start rf-gap-4", children: [
2336
+ /* @__PURE__ */ jsx24("div", { className: "rf-flex-shrink-0 rf-mt-0.5", children: /* @__PURE__ */ jsx24("div", { className: "rf-w-8 rf-h-8 rf-rounded-full rf-bg-green-100 rf-flex rf-items-center rf-justify-center", children: /* @__PURE__ */ jsx24(Check3, { className: "rf-h-5 rf-w-5 rf-text-green-600" }) }) }),
2337
+ /* @__PURE__ */ jsxs17("div", { className: "rf-flex-1", children: [
2338
+ /* @__PURE__ */ jsx24("p", { className: "rf-text-sm rf-font-medium rf-text-muted-foreground", children: "Last Completed" }),
2339
+ /* @__PURE__ */ jsxs17("p", { className: "rf-font-medium rf-text-green-600", children: [
2340
+ lastCompletedStep.order_step_id,
2341
+ ". ",
2342
+ lastCompletedStep.title
2343
+ ] })
2344
+ ] })
2345
+ ] }),
2346
+ lastCompletedStep && activeStep && /* @__PURE__ */ jsx24("div", { className: "rf-pl-4", children: /* @__PURE__ */ jsx24(ArrowDown2, { className: "rf-h-5 rf-w-5 rf-text-muted-foreground" }) }),
2347
+ activeStep && /* @__PURE__ */ jsxs17("div", { className: "rf-flex rf-items-start rf-gap-4", children: [
2348
+ /* @__PURE__ */ jsx24("div", { className: "rf-flex-shrink-0 rf-mt-0.5", children: /* @__PURE__ */ jsx24("div", { className: "rf-w-8 rf-h-8 rf-rounded-full rf-bg-blue-100 rf-flex rf-items-center rf-justify-center", children: loading ? /* @__PURE__ */ jsx24(Loader22, { className: "rf-h-5 rf-w-5 rf-text-blue-600 rf-animate-spin" }) : /* @__PURE__ */ jsx24("div", { className: "rf-h-2.5 rf-w-2.5 rf-rounded-full rf-bg-blue-600" }) }) }),
2349
+ /* @__PURE__ */ jsxs17("div", { className: "rf-flex-1", children: [
2350
+ /* @__PURE__ */ jsx24("p", { className: "rf-text-sm rf-font-medium rf-text-muted-foreground", children: "Current Step" }),
2351
+ /* @__PURE__ */ jsxs17("p", { className: "rf-font-medium rf-text-blue-600", children: [
2352
+ activeStep.order_step_id,
2353
+ ". ",
2354
+ activeStep.title
2355
+ ] })
2356
+ ] })
2357
+ ] })
2358
+ ] }),
2359
+ /* @__PURE__ */ jsx24("div", { className: "rf-flex rf-justify-end rf-gap-3 rf-mt-auto", children: onCancel && /* @__PURE__ */ jsx24(Button, { variant: "outline", onClick: onCancel, className: "rf-px-6", children: "Cancel" }) })
2360
+ ] });
2361
+ };
2362
+
2363
+ // lib/components/OrderDialog/OrderDialog.tsx
2364
+ import "ky";
2365
+ import { jsx as jsx25, jsxs as jsxs18 } from "react/jsx-runtime";
2366
+ var queryClient = new QueryClient();
2367
+ var OrderDialog = ({
2368
+ isOpen,
2369
+ onClose,
2370
+ stage,
2371
+ setStage,
2372
+ circuitJson
2373
+ }) => {
2374
+ const [order, setOrder] = useState7(null);
2375
+ const [loading, setLoading] = useState7(false);
2376
+ const createOrder = async (sessionId) => {
2377
+ const { order: order2 } = await registryKy.post("orders/create", {
2378
+ json: {
2379
+ circuit_json: circuitJson
2380
+ },
2381
+ headers: {
2382
+ Authorization: `Bearer ${sessionId ?? "account-1234"}`
2383
+ }
2384
+ }).json();
2385
+ return order2;
2386
+ };
2387
+ const handleInitialContinue = async () => {
2388
+ const order2 = await createOrder();
2389
+ setOrder(order2);
2390
+ setStage("progress");
2391
+ };
2392
+ return /* @__PURE__ */ jsx25(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx25(AlertDialog, { open: isOpen, onOpenChange: onClose, children: /* @__PURE__ */ jsx25(AlertDialogContent, { className: "!rf-max-w-[660px] !rf-p-0", children: /* @__PURE__ */ jsxs18("div", { className: "rf-relative rf-w-full", children: [
2393
+ stage === "initial" && /* @__PURE__ */ jsx25(
2394
+ InitialOrderScreen,
2395
+ {
2396
+ onCancel: onClose,
2397
+ onContinue: handleInitialContinue
2398
+ }
2399
+ ),
2400
+ stage === "progress" && order?.order_id && /* @__PURE__ */ jsx25(
2401
+ StepwiseProgressPanel,
2402
+ {
2403
+ onCancel: onClose,
2404
+ loading,
2405
+ orderId: order?.order_id,
2406
+ setStage
2407
+ }
2408
+ ),
2409
+ stage === "checkout" && /* @__PURE__ */ jsx25(
2410
+ CheckoutOrder,
2411
+ {
2412
+ finalCost: 0,
2413
+ onConfirmCheckout: onClose,
2414
+ onCancel: onClose
2415
+ }
2416
+ )
2417
+ ] }) }) }) });
2418
+ };
2419
+
2420
+ // lib/components/OrderDialog/CliOrderDialog.tsx
2421
+ import { jsx as jsx26 } from "react/jsx-runtime";
2422
+ var CliOrderDialog = ({
2423
+ isOpen,
2424
+ onClose,
2425
+ stage,
2426
+ setStage
2427
+ }) => {
2428
+ const circuitJson = useRunFrameStore((state) => state.circuitJson);
2429
+ return /* @__PURE__ */ jsx26(
2430
+ OrderDialog,
2431
+ {
2432
+ isOpen,
2433
+ onClose,
2434
+ stage,
2435
+ setStage,
2436
+ circuitJson
2437
+ }
2438
+ );
2439
+ };
2440
+
2441
+ // lib/components/OrderDialog/useOrderDialog.tsx
2442
+ import { useState as useState8 } from "react";
2443
+ var useOrderDialogCli = () => {
2444
+ const [isOpen, setIsOpen] = useState8(false);
2445
+ const [stage, setStage] = useState8("initial");
2446
+ const handleClose = () => {
2447
+ setIsOpen(false);
2448
+ setStage("initial");
2449
+ };
2450
+ return {
2451
+ isOpen,
2452
+ stage,
2453
+ open: () => setIsOpen(true),
2454
+ close: handleClose,
2455
+ setStage,
2456
+ OrderDialog: CliOrderDialog
2457
+ };
2458
+ };
2459
+ var useOrderDialog = () => {
2460
+ useStyles();
2461
+ const [isOpen, setIsOpen] = useState8(false);
2462
+ const [stage, setStage] = useState8("initial");
2463
+ const handleClose = () => {
2464
+ setIsOpen(false);
2465
+ setStage("initial");
2466
+ };
2467
+ return {
2468
+ isOpen,
2469
+ stage,
2470
+ open: () => setIsOpen(true),
2471
+ close: handleClose,
2472
+ setStage,
2473
+ OrderDialog
2474
+ };
2475
+ };
2476
+
1348
2477
  export {
1349
2478
  cn,
1350
2479
  Tabs,
1351
2480
  TabsList,
1352
2481
  TabsTrigger,
1353
- buttonVariants,
1354
2482
  Button,
1355
2483
  DropdownMenu,
1356
2484
  DropdownMenuTrigger,
@@ -1364,6 +2492,19 @@ export {
1364
2492
  BomTable,
1365
2493
  PcbViewerWithContainerHeight,
1366
2494
  CircuitJsonPreview,
2495
+ debug_default,
2496
+ API_BASE,
2497
+ useRunFrameStore,
2498
+ AlertDialog,
2499
+ AlertDialogContent,
2500
+ AlertDialogHeader,
2501
+ AlertDialogFooter,
2502
+ AlertDialogTitle,
2503
+ AlertDialogDescription,
2504
+ AlertDialogCancel,
2505
+ Input,
2506
+ useOrderDialogCli,
2507
+ useOrderDialog,
1367
2508
  CadViewer2 as CadViewer,
1368
2509
  PCBViewer3 as PCBViewer,
1369
2510
  SchematicViewer2 as SchematicViewer