feat: add card rotation, customer lookup, and concurrent eligibility checks
Add encrypted card pool management, persisted card and outbound rotation, and per-card decline cooldowns. Improve customer and redemption-code lookup, recovery controls, and filtering; rebuild frontend assets and refresh mock screenshots. Give read-only eligibility checks four independent slots so payment processing no longer blocks them. Cover concurrency, slot cleanup, card rotation, and lookup behavior with tests.
This commit is contained in:
47 files changed
+3033
-501
No files matched your search
@@ -37,7 +37,7 @@ npm run preview
|
||||
部署前请先准备好以下四样东西,配置向导会逐项询问:
|
||||
|
||||
1. **X 登录 Cookie**(`auth_token` 和 `ct0`):在浏览器登录 x.com 后,按 F12 打开开发者工具 → Application(应用)→ Cookies → `https://x.com`,复制这两项的值。这是系统以你的 X 账号身份发起赠送的凭据。
|
||||
2. **一张用于付款的银行卡**:卡号、有效期、CVC,以及发卡行登记的持卡人姓名、账单邮箱和账单国家(两位代码,如 `BD`)。请只填真实信息。
|
||||
2. **用于付款的银行卡(一张或多张)**:卡号、有效期、CVC,以及发卡行登记的持卡人姓名、账单邮箱和账单国家(两位代码,如 `BD`)。多张卡会在服务端加密保存并随机轮换,新卡可复用同一账单资料。请只填真实信息。
|
||||
3. **代理(可选)**:服务器能直接访问 x.com 就选「直连」;否则准备一个代理节点。支持 sing-box 的任意 outbound 类型(anytls、socks、http、shadowsocks、vmess、vless、trojan 等),也可以直接粘贴完整 sing-box 配置。
|
||||
4. **Stripe 公钥**:X 结账页面使用的 `pk_live_` 开头公钥。使用默认 X Premium 目录时向导会说明;它与商户、商品、价格一起保存在「目录」配置中,也可以完全自定义。
|
||||
|
||||
@@ -65,7 +65,7 @@ go build -tags with_quic,with_utls -o bin/xgift-web ./cmd/xgift-web
|
||||
|
||||
1. **密码文件** — 自动生成一个随机密码用于加密保管库,保存在你指定的路径(默认 `sqlite/vault-password`,仅本人可读)。**请务必备份这个文件,丢失后所有加密数据无法恢复。**
|
||||
2. **X 凭据** — 粘贴第一步准备的两个 Cookie。
|
||||
3. **支付卡** — 输入卡信息和账单信息(卡号会自动校验)。
|
||||
3. **支付卡** — 输入卡信息和账单信息(卡号会自动校验)。想启用多卡轮换,向导完成后用 `xgift cards add` 追加更多卡,缺少的账单字段会自动继承。
|
||||
4. **代理** — 选直连、按提示填 AnyTLS 节点,或粘贴 sing-box 配置;保存前会实际启动验证配置是否有效。
|
||||
5. **Stripe 公钥** — 粘贴 `pk_live_` 公钥。
|
||||
6. **商品目录** — 直接回车使用 X Premium 默认目录(3/6 个月套餐),或自定义商户、币种和套餐。
|
||||
@@ -123,11 +123,15 @@ curl https://你的域名/healthz # {"ok":true,...} 即成功
|
||||
更新配置用 `put`(从标准输入读取新值):
|
||||
|
||||
```sh
|
||||
echo '新的ct0等JSON' | ./bin/xgift put --name cookies # 还有 card / proxy / api-auth
|
||||
./bin/xgift cards list # 查看卡池和当前轮换组合(只显示尾号)
|
||||
echo '{"number":"...","exp_month":"05","exp_year":"2031","cvc":"123"}' | ./bin/xgift cards add
|
||||
echo '新的ct0等JSON' | ./bin/xgift put --name cookies # 还有 card / cards / proxy / api-auth
|
||||
echo 'pk_live_新公钥' | ./bin/xgift put --name stripe-key
|
||||
echo '{"merchant":"acct_...","currency":"bdt","plans":[...]}' | ./bin/xgift put --name catalog
|
||||
```
|
||||
|
||||
付款卡按「卡 × 节点」组合随机轮换:每 3 个连续订单使用同一组合;任意订单被拒后立即换组合,被拒的那张卡进入 30 分钟冷却(其他卡继续轮换),补单也走同一逻辑。支付方明确 `do_not_try_again` 时该卡永久封锁直到显式解除。`cards add` 追加或更新(同卡号替换),`cards remove --last4 1234` 移除,`cards rotate` 立即结束当前组合,`cards unblock` 清除冷却与永久封锁。
|
||||
|
||||
## 常见问题
|
||||
|
||||
**密码文件丢了怎么办?** 无法恢复。加密数据全部作废,需要删除 `vault.db` 后重新运行 `xgift setup`。请把它和数据库一起备份。
|
||||
@@ -136,7 +140,7 @@ echo '{"merchant":"acct_...","currency":"bdt","plans":[...]}' | ./bin/xgift put
|
||||
|
||||
**想暂停充值?** 把 `site.env` 里 `XGIFT_PAYMENTS_ENABLED` 改为 `false` 并重启服务。用户兑换会被婉拒,兑换码不消耗。
|
||||
|
||||
**付款被拒怎么办?** 明确拒付会显示失败说明并阻止重复提交,不再显示自动核实。网页和 CLI 在同一个 `checkout.lock` 下执行付款,提交间隔至少 30 秒,重启仍保留间隔。普通拒付只标记该订单失败,不因连续次数暂停全站;支付端明确返回 `do_not_try_again` 时保留停止重试保护。处理付款方式后,管理员可执行 `xgift resume-payments`(指定生产环境的 `--db` 和 `--password-file`)解除普通旧暂停(不能解除支付方明确禁止重试的暂停);该命令不付款,也不会修改 `XGIFT_PAYMENTS_ENABLED`。手动完成原账单后,可查询原订单以核对成功状态。
|
||||
**付款被拒怎么办?** 明确拒付会显示失败说明并阻止重复提交,不再显示自动核实。网页和 CLI 在同一个 `checkout.lock` 下执行付款,提交间隔至少 30 秒,重启仍保留间隔。付款按「卡 × 节点」组合随机轮换,每 3 个连续订单使用同一组合;普通拒付会立即结束当前组合,被拒那张卡进入 30 分钟冷却(其他卡继续轮换,可用卡不足时自动回退),下一次提交(含补单)自动换到新的卡和节点,不因连续次数暂停全站。支付端明确返回 `do_not_try_again` 时只封锁被拒的那张卡;仅当所有卡都被永久封锁时才暂停全站,可用 `xgift cards unblock` 显式解除(不能通过补单确认框解除)。该命令不付款,也不会修改 `XGIFT_PAYMENTS_ENABLED`。手动完成原账单后,可查询原订单以核对成功状态。
|
||||
|
||||
**付款结果不明怎么办?** 系统宁可标记「待核实」也不会重复扣款。用户用原兑换码点「重新检查并继续兑换」即可自动核对,确认成功后自动补上状态。
|
||||
|
||||
@@ -150,7 +154,7 @@ echo '{"merchant":"acct_...","currency":"bdt","plans":[...]}' | ./bin/xgift put
|
||||
|
||||
### 管理员手动补单
|
||||
|
||||
登录 `/admin`,使用「预览并补单」查看所有 `review` 订单、每笔金额和当前默认卡尾号,勾选确认后点击「确认付款并启动补单」。此操作会发起真实付款,独立于公开充值入口的 `XGIFT_PAYMENTS_ENABLED` 开关;预览、状态查询、部署或服务重启均不会启动付款。预览有效期为 10 分钟,卡配置或订单内容发生变化时必须重新预览。
|
||||
登录 `/admin`,使用「预览并补单」查看所有 `review` 订单、每笔金额和当前轮换卡尾号,勾选确认后点击「确认付款并启动补单」。补单与普通付款共用同一套卡 × 节点轮换逻辑:被拒订单会换到新组合,同一批次的后续订单继续沿用新组合。此操作会发起真实付款,独立于公开充值入口的 `XGIFT_PAYMENTS_ENABLED` 开关;预览、状态查询、部署或服务重启均不会启动付款。预览有效期为 10 分钟,卡池配置或订单内容发生变化时必须重新预览。
|
||||
|
||||
补单在服务器后台串行执行,订单之间至少等待 30 秒,并保留全局付款间隔。每批每单最多尝试一次;已付款只同步结果,未知付款结果、银行验证、禁止重试指令和不匹配的账单不会重付。有效会话会复用并重新核验商户、客户、套餐、金额及未收款/未授权金额证据。旧会话失效时,管理员必须确认已核对原订单未扣款;系统还要求原始明确拒付、对应的失败查询记录,以及再次通过的账号资格和价格检查,才会归档旧订单并生成新链接。未知付款结果、禁止重试指令不会因该确认而放行。每个原会话最多允许 3 次人工重试。普通拒付不再累计触发全站暂停;支付方明确禁止重试的暂停不能从此按钮解除。
|
||||
|
||||
|
||||
+114
-28
@@ -34,12 +34,13 @@ func run() error {
|
||||
// Permit the requested `xgift username --pay` spelling as well as global flags.
|
||||
args := os.Args[1:]
|
||||
command := ""
|
||||
sub := ""
|
||||
rest := []string{}
|
||||
for i := 0; i < len(args); i++ {
|
||||
a := args[i]
|
||||
if strings.HasPrefix(a, "-") {
|
||||
rest = append(rest, a)
|
||||
if a == "--db" || a == "--password-file" || a == "--profile" || a == "--port" || a == "--name" || a == "--months" {
|
||||
if a == "--db" || a == "--password-file" || a == "--profile" || a == "--port" || a == "--name" || a == "--months" || a == "--last4" {
|
||||
i++
|
||||
if i >= len(args) {
|
||||
return errors.New("missing flag value")
|
||||
@@ -48,6 +49,8 @@ func run() error {
|
||||
}
|
||||
} else if command == "" {
|
||||
command = a
|
||||
} else if command == "cards" && sub == "" {
|
||||
sub = a
|
||||
} else {
|
||||
return errors.New("unexpected argument")
|
||||
}
|
||||
@@ -67,12 +70,13 @@ func run() error {
|
||||
profile := f.String("profile", "Default", "Chrome directory name")
|
||||
port := f.Int("port", 0, "local proxy port; default automatic (proxy command: 18791)")
|
||||
months := f.Int("months", 6, "gift duration in months; must match a plan in the catalog record")
|
||||
last4 := f.String("last4", "", "card tail for cards remove")
|
||||
retire := f.Bool("retire-canceled", false, "archive an inactive, canceled, unpaid order after read-only verification")
|
||||
inspect := f.Bool("inspect", false, "read the existing Stripe order status without paying")
|
||||
pay := f.Bool("pay", false, "pay only at the exact catalog plan total")
|
||||
name := f.String("name", "", "secret name for put")
|
||||
f.Usage = func() {
|
||||
fmt.Fprintln(f.Output(), "Usage: xgift <setup|init|status|billing|import-chrome|put|proxy|check|check-payment-outbounds|resume-payments|username> [flags]\nsetup is the interactive first-time wizard; init reads a JSON object from stdin; put reads one JSON value from stdin (stripe-key: the raw pk_live_ key; catalog: merchant/plan catalog JSON; payment-outbounds: an outbound array). check-payment-outbounds probes public endpoints without paying.")
|
||||
fmt.Fprintln(f.Output(), "Usage: xgift <setup|init|status|billing|cards|import-chrome|put|proxy|check|check-payment-outbounds|resume-payments|username> [flags]\nsetup is the interactive first-time wizard; init reads a JSON object from stdin; put reads one JSON value from stdin (stripe-key: the raw pk_live_ key; catalog: merchant/plan catalog JSON; payment-outbounds: an outbound array; cards: a card array). cards list|add|remove|unblock|rotate manages the encrypted payment card pool. check-payment-outbounds probes public endpoints without paying.")
|
||||
f.PrintDefaults()
|
||||
}
|
||||
if err := f.Parse(rest); err != nil {
|
||||
@@ -146,6 +150,8 @@ func run() error {
|
||||
}
|
||||
defer v.Close()
|
||||
switch command {
|
||||
case "cards":
|
||||
return runCards(v, sub, *last4)
|
||||
case "check-payment-outbounds":
|
||||
failed := false
|
||||
enc := json.NewEncoder(os.Stdout)
|
||||
@@ -177,39 +183,18 @@ func run() error {
|
||||
fmt.Println("Automatic payment pause cleared; payment spacing remains enforced.")
|
||||
return nil
|
||||
case "billing":
|
||||
raw, e := v.Get("card")
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer clear(raw)
|
||||
var c map[string]any
|
||||
if e = json.Unmarshal(raw, &c); e != nil {
|
||||
return e
|
||||
}
|
||||
var fields map[string]string
|
||||
if e = json.NewDecoder(io.LimitReader(os.Stdin, 65536)).Decode(&fields); e != nil {
|
||||
if e := json.NewDecoder(io.LimitReader(os.Stdin, 65536)).Decode(&fields); e != nil {
|
||||
return errors.New("billing expects a JSON object on stdin")
|
||||
}
|
||||
for n, value := range fields {
|
||||
switch n {
|
||||
case "billing_name", "email", "billing_country", "billing_postal_code", "billing_address_line1", "billing_address_line2", "billing_city", "billing_state":
|
||||
c[n] = value
|
||||
default:
|
||||
return errors.New("unsupported billing field")
|
||||
}
|
||||
}
|
||||
raw, e = json.Marshal(c)
|
||||
n, e := checkout.UpdateCardBilling(v, fields)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer clear(raw)
|
||||
if e = v.Put("card", raw); e != nil {
|
||||
return e
|
||||
}
|
||||
fmt.Println("Billing information saved in encrypted SQLite")
|
||||
fmt.Printf("Billing information saved in encrypted SQLite for %d card(s)\n", n)
|
||||
return nil
|
||||
case "status":
|
||||
for _, n := range []string{"cookies", "card", "proxy"} {
|
||||
for _, n := range []string{"cookies", "proxy"} {
|
||||
b, e := v.Get(n)
|
||||
if e != nil {
|
||||
return fmt.Errorf("record %s is missing; run setup or put --name %s", n, n)
|
||||
@@ -220,6 +205,20 @@ func run() error {
|
||||
clear(b)
|
||||
fmt.Printf("%s: encrypted record verified\n", n)
|
||||
}
|
||||
status, e := checkout.CardsStatus(v)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
usable := 0
|
||||
for _, card := range status {
|
||||
if card.Usable {
|
||||
usable++
|
||||
}
|
||||
}
|
||||
if usable == 0 {
|
||||
return checkout.ErrNoUsableCard
|
||||
}
|
||||
fmt.Printf("cards: %d encrypted record(s), %d usable\n", len(status), usable)
|
||||
raw, e := v.Get("api-auth")
|
||||
if e != nil {
|
||||
return errors.New("record api-auth is missing; fix with put --name api-auth")
|
||||
@@ -285,6 +284,18 @@ func run() error {
|
||||
return errors.New("stdin must be valid JSON")
|
||||
}
|
||||
return v.Put(*name, b)
|
||||
case "cards":
|
||||
b, e := io.ReadAll(io.LimitReader(os.Stdin, 1024*1024))
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
defer clear(b)
|
||||
n, e := checkout.SetCardRecords(v, b)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
fmt.Printf("Card set replaced: %d validated cards\n", n)
|
||||
return nil
|
||||
case "stripe-key":
|
||||
b, e := io.ReadAll(io.LimitReader(os.Stdin, 4096))
|
||||
if e != nil {
|
||||
@@ -307,7 +318,7 @@ func run() error {
|
||||
}
|
||||
return v.Put(*name, b)
|
||||
default:
|
||||
return errors.New("--name must be proxy, payment-outbounds, card, cookies, api-auth, stripe-key or catalog")
|
||||
return errors.New("--name must be proxy, payment-outbounds, card, cards, cookies, api-auth, stripe-key or catalog")
|
||||
}
|
||||
}
|
||||
if command != "proxy" && command != "check" && !regexp.MustCompile(`^@?[A-Za-z0-9_]{1,15}$`).MatchString(command) {
|
||||
@@ -375,3 +386,78 @@ func run() error {
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func runCards(v *vault.Vault, sub, last4 string) error {
|
||||
switch sub {
|
||||
case "", "list":
|
||||
status, err := checkout.CardsStatus(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
rotation, err := checkout.PaymentRotationStatus(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("卡池:%d 张(每 %d 个连续订单使用同一卡+节点组合;被拒后立即轮换)\n", rotation.Cards, rotation.BatchSize)
|
||||
for i, s := range status {
|
||||
line := fmt.Sprintf(" %d) 尾号 %s", i+1, s.Last4)
|
||||
if s.Usable {
|
||||
line += " 可用"
|
||||
} else {
|
||||
line += " 不可用:" + s.Problem
|
||||
}
|
||||
if s.Blocked != "" {
|
||||
if s.CoolingSeconds > 0 {
|
||||
line += fmt.Sprintf("(被拒冷却:%s,剩 %d 分钟)", s.Blocked, (s.CoolingSeconds+59)/60)
|
||||
} else {
|
||||
line += "(已封锁:" + s.Blocked + ")"
|
||||
}
|
||||
}
|
||||
fmt.Println(line)
|
||||
}
|
||||
if rotation.CardLast4 == "" {
|
||||
fmt.Println("当前轮换组合:未开始(下一笔付款时随机选择)")
|
||||
} else {
|
||||
node := rotation.Node
|
||||
if node == "" {
|
||||
node = "direct"
|
||||
}
|
||||
fmt.Printf("当前轮换组合:尾号 %s × %s(已用 %d/%d)\n", rotation.CardLast4, node, rotation.Used, rotation.BatchSize)
|
||||
}
|
||||
return nil
|
||||
case "add":
|
||||
b, err := io.ReadAll(io.LimitReader(os.Stdin, 1<<20))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer clear(b)
|
||||
total, err := checkout.AddCardRecords(v, b)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("卡池已保存:共 %d 张。缺少的账单字段已从现有卡继承。\n", total)
|
||||
return nil
|
||||
case "remove":
|
||||
remaining, err := checkout.RemoveCardRecord(v, last4)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("已移除尾号 %s;卡池剩余 %d 张\n", last4, remaining)
|
||||
return nil
|
||||
case "unblock":
|
||||
cleared, err := checkout.UnblockPaymentCards(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("已解除 %d 张卡的封锁;若仍有可用卡,付款保护暂停已同步解除\n", cleared)
|
||||
return nil
|
||||
case "rotate":
|
||||
if err := checkout.ResetPaymentRotation(v); err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Println("已结束当前轮换批次;下一笔付款将随机选择新的卡+节点组合")
|
||||
return nil
|
||||
default:
|
||||
return errors.New("cards expects list, add, remove --last4 XXXX, unblock or rotate")
|
||||
}
|
||||
}
|
||||
@@ -75,14 +75,25 @@ PY
|
||||
|
||||
包含 selector、urltest 等分组的订阅须先移除这些元素,仅保留独立代理节点。运行程序不自动拉取订阅,避免未经核验的订阅更新改变付款路径。
|
||||
|
||||
## 节点选择和订单绑定
|
||||
## 卡池轮换、节点选择和订单绑定
|
||||
|
||||
付款卡保存在加密的 `cards` 数组(兼容旧的单张 `card` 记录),Stripe 付款按「卡 × 节点」组合随机轮换:
|
||||
|
||||
- 每 3 个连续付款订单使用同一组合(不按客户,按提交顺序)。第 4 个订单重新随机选择卡和可用节点;同一张卡不会连续被选为相邻组合(可用卡足够时)。
|
||||
- 任一订单被银行拒付后,当前组合立即作废;下一次提交(包括管理员补单)自动换到另一张卡和一个可用节点。被拒的那张卡进入 30 分钟冷却,期间不再参与轮换;其他卡不够用时会自动回退重新启用。普通拒付不再因累计次数暂停全站,也不影响其他组合。
|
||||
- 只有支付方明确返回 `do_not_try_again` 时才永久封锁对应那张卡;其余卡继续轮换,全部卡都被永久封锁才暂停全站,可用 `xgift cards unblock` 显式解除(同时清除拒绝冷却)。
|
||||
- 旧单卡时代的已拒订单没有卡指纹记录,首次补单会按旧 `card` 记录给对应卡补上冷却,避免用旧卡反复重试。
|
||||
- 补单与普通付款共用同一套轮换逻辑;已被拒订单不会重复使用原卡重试,而未提交付款的订单重复尝试会继续沿用已绑定的组合,不重复占用轮换名额。
|
||||
- 卡池变化(增删卡)会形成新的集合指纹,自动重置支付保护状态和后台补单预览;仅轮换不会改变指纹。CLI 用 `xgift cards list|add|remove|unblock|rotate` 管理。
|
||||
|
||||
节点选择与旧版一致:
|
||||
|
||||
- 新绑定订单首次进入 Stripe 流程时,从未冷却的池内节点随机选择,`direct` 与代理均可参与。若有不同 `server` 的节点,会避开上一新订单的服务器;如果全部同服务器,则尽量避开上一节点。
|
||||
- 一次批量补单中的不同客户分别选择。随机选择不保证各节点次数相等;不同协议节点也可能共享同一公网 IP。
|
||||
- 选择发生在第一个 Stripe 请求前,所以“仅生成链接”中的 Stripe 核验也可能建立节点绑定。
|
||||
- `stripe-route:<recipient_id>` 保存加密的节点配置快照、节点指纹和时间,正常情况下持续沿用。节点因连接故障进入冷却后,可原子归档到 `stripe-route-history:*` 并切换到可用出口。后台显示 `direct` 或 `node-` 加指纹前 12 位,完整凭据不返回网页。
|
||||
- `stripe-route:<recipient_id>` 保存加密的节点配置快照、节点指纹、卡指纹和时间,正常情况下持续沿用。节点因连接故障进入冷却后,可原子归档到 `stripe-route-history:*` 并切换到可用出口;卡指纹保持不变。后台显示 `direct` 或 `node-` 加指纹前 12 位,完整凭据不返回网页。
|
||||
- 以前没有节点绑定的待处理订单,在功能启用后首次访问 Stripe 时建立绑定。绑定不代表已付款。
|
||||
- 明确银行卡拒付不会自动换节点重付。金额校验、幂等、付款间隔和支付方禁止重试指令继续生效;普通拒付不再因累计两次而触发全站暂停。
|
||||
- 明确银行卡拒付不会在同一个组合上重复扣款。金额校验、幂等、付款间隔和支付方禁止重试指令继续生效。
|
||||
|
||||
## 网络重试与 6 小时冷却
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 215 KiB After Width: | Height: | Size: 238 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 214 KiB After Width: | Height: | Size: 238 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 64 KiB After Width: | Height: | Size: 93 KiB |
@@ -121,6 +121,49 @@ createServer(async (req, res) => {
|
||||
return;
|
||||
}
|
||||
if (req.method !== "POST") {
|
||||
if (req.method === "GET" && url.pathname === "/api/admin/recovery") {
|
||||
json(200, {
|
||||
batch: null,
|
||||
network: { mode: "direct", nodes: 1 },
|
||||
summary: {
|
||||
review: codes.filter((code) => code.status === "review").length,
|
||||
processing: codes.filter((code) => code.status === "processing")
|
||||
.length,
|
||||
},
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (req.method === "GET" && url.pathname === "/api/admin/customer") {
|
||||
const key = url.searchParams.get("id") || "";
|
||||
const user = (url.searchParams.get("username") || "")
|
||||
.replace(/^@/, "")
|
||||
.toLowerCase();
|
||||
const found = codes.find(
|
||||
(code) =>
|
||||
(key && code.id === key) || (user && code.username === user),
|
||||
);
|
||||
if (!found) {
|
||||
json(404, { message: "没有找到对应的订单,请核对后重试。" });
|
||||
return;
|
||||
}
|
||||
json(200, {
|
||||
order: {
|
||||
id: found.id,
|
||||
username: found.username,
|
||||
hint: found.hint,
|
||||
months: found.months,
|
||||
status: found.status,
|
||||
message: found.message,
|
||||
batch: found.batch,
|
||||
},
|
||||
code: plaintext.get(found.id) || "",
|
||||
checkout_url: "",
|
||||
previous_checkout_url: "",
|
||||
can_recover: false,
|
||||
replacement_count: 0,
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (req.method === "GET" && url.pathname === "/api/admin/stats") {
|
||||
const daily = [];
|
||||
for (let offset = 29; offset >= 0; offset--) {
|
||||
@@ -174,8 +217,11 @@ createServer(async (req, res) => {
|
||||
}
|
||||
}
|
||||
const body = JSON.parse(raw);
|
||||
if (
|
||||
url.pathname === "/api/admin/folders" ||
|
||||
if (url.pathname.startsWith("/api/admin/recovery/")) {
|
||||
json(503, { message: "本地模拟预览不提供补单操作。" });
|
||||
return;
|
||||
}
|
||||
if (url.pathname === "/api/admin/folders" ||
|
||||
url.pathname === "/api/admin/folders/rename"
|
||||
) {
|
||||
const name = typeof body.name === "string" ? body.name.trim() : "";
|
||||
@@ -304,6 +350,30 @@ createServer(async (req, res) => {
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (url.pathname === "/api/admin/lookup") {
|
||||
const full =
|
||||
typeof body.code === "string" ? body.code.trim().toUpperCase() : "";
|
||||
if (!/^XG-[A-F0-9]{48}$/.test(full)) {
|
||||
json(400, { message: "请填写 XG- 开头、后接 48 位字符的完整兑换码。" });
|
||||
return;
|
||||
}
|
||||
// Fixed demo hit so a found result can be previewed without generating.
|
||||
if (full === "XG-" + "5".repeat(48)) {
|
||||
json(200, { ...codes[2], progress: 100, updated: now });
|
||||
return;
|
||||
}
|
||||
const entry = [...plaintext.entries()].find(
|
||||
([, value]) => value === full,
|
||||
);
|
||||
const found = entry && codes.find((code) => code.id === entry[0]);
|
||||
json(
|
||||
found ? 200 : 404,
|
||||
found
|
||||
? { ...found, updated: found.created, progress: 0 }
|
||||
: { message: "没有找到这个兑换码,请核对后重试。" },
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (url.pathname === "/api/admin/codes/copy") {
|
||||
const code = plaintext.get(body.id);
|
||||
json(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { Alert, Box, Button, Stack, Typography } from "@mui/material";
|
||||
import ContentCopyRounded from "@mui/icons-material/ContentCopyRounded";
|
||||
import CheckRounded from "@mui/icons-material/CheckRounded";
|
||||
@@ -6,6 +6,12 @@ import CheckRounded from "@mui/icons-material/CheckRounded";
|
||||
export function CopyableCodes({ codes }: { codes: string[] }) {
|
||||
const [copied, setCopied] = useState<number | "all" | null>(null);
|
||||
const [error, setError] = useState(false);
|
||||
// The ✓ marks a recent copy; clear it so a later visit does not read as fresh.
|
||||
useEffect(() => {
|
||||
if (copied === null) return;
|
||||
const timer = setTimeout(() => setCopied(null), 5000);
|
||||
return () => clearTimeout(timer);
|
||||
}, [copied]);
|
||||
async function copy(index: number | "all") {
|
||||
try {
|
||||
await navigator.clipboard.writeText(
|
||||
@@ -43,6 +49,7 @@ export function CopyableCodes({ codes }: { codes: string[] }) {
|
||||
<Box
|
||||
component="ul"
|
||||
aria-label="新生成的兑换码"
|
||||
tabIndex={0}
|
||||
sx={{
|
||||
m: 0,
|
||||
p: 0,
|
||||
|
||||
@@ -13,6 +13,8 @@ import {
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import { adminApi } from "./adminApi";
|
||||
import { codeStatus } from "./codeStatus";
|
||||
import PersonSearchRounded from "@mui/icons-material/PersonSearchRounded";
|
||||
|
||||
type Detail = {
|
||||
order: {
|
||||
@@ -81,9 +83,9 @@ export function CustomerPanel({
|
||||
async function copy() {
|
||||
try {
|
||||
await navigator.clipboard.writeText(detail?.code || "");
|
||||
setNotice("完整卡密已复制。");
|
||||
setNotice("完整兑换码已复制。");
|
||||
} catch {
|
||||
setNotice("复制失败,请选中下方完整卡密手动复制。");
|
||||
setNotice("复制失败,请选中下方完整兑换码手动复制。");
|
||||
}
|
||||
}
|
||||
function prepare(mode: "links" | "pay") {
|
||||
@@ -94,10 +96,22 @@ export function CustomerPanel({
|
||||
}
|
||||
return (
|
||||
<>
|
||||
<Paper variant="outlined" sx={{ p: { xs: 2, sm: 3 }, mb: 3 }}>
|
||||
<Typography variant="h2" sx={{ fontSize: 21 }}>
|
||||
按客户查卡密 / 单独补单
|
||||
</Typography>
|
||||
<Paper
|
||||
variant="outlined"
|
||||
component="section"
|
||||
aria-labelledby="customer-panel-title"
|
||||
sx={{ p: { xs: 2, sm: 3 }, height: "100%" }}
|
||||
>
|
||||
<Stack direction="row" spacing={1} alignItems="center">
|
||||
<PersonSearchRounded color="primary" aria-hidden="true" />
|
||||
<Typography
|
||||
id="customer-panel-title"
|
||||
variant="h2"
|
||||
sx={{ fontSize: 21 }}
|
||||
>
|
||||
按客户查询
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Box
|
||||
component="form"
|
||||
onSubmit={(e) => {
|
||||
@@ -115,6 +129,7 @@ export function CustomerPanel({
|
||||
size="small"
|
||||
fullWidth
|
||||
autoComplete="off"
|
||||
slotProps={{ htmlInput: { maxLength: 16, spellCheck: false } }}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
@@ -127,7 +142,7 @@ export function CustomerPanel({
|
||||
</Stack>
|
||||
</Box>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mt: 1 }}>
|
||||
直接查看客户对应的完整卡密和付款链接,无需按批次翻页。
|
||||
直接查看客户对应的完整兑换码和付款链接,无需按批次翻页。
|
||||
</Typography>
|
||||
</Paper>
|
||||
<Dialog
|
||||
@@ -136,34 +151,35 @@ export function CustomerPanel({
|
||||
fullWidth
|
||||
maxWidth="sm"
|
||||
aria-labelledby="customer-title"
|
||||
aria-describedby="customer-dialog-description"
|
||||
>
|
||||
<DialogTitle id="customer-title">
|
||||
{detail ? `@${detail.order.username} 的订单` : "客户订单详情"}
|
||||
{detail
|
||||
? detail.order.username
|
||||
? `@${detail.order.username} 的订单`
|
||||
: "兑换码详情"
|
||||
: error
|
||||
? "查询结果"
|
||||
: "客户订单详情"}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContent id="customer-dialog-description">
|
||||
{busy && <Typography>正在读取订单…</Typography>}
|
||||
{error && <Alert severity="error">{error}</Alert>}
|
||||
{error && <Alert severity="error" role="alert">{error}</Alert>}
|
||||
{detail && (
|
||||
<Stack spacing={2}>
|
||||
<Typography>
|
||||
{detail.order.months} 个月 · {detail.order.batch || "未分类"} ·{" "}
|
||||
{(
|
||||
{
|
||||
review: "待处理",
|
||||
succeeded: "已完成",
|
||||
processing: "处理中",
|
||||
active: "未使用",
|
||||
revoked: "已停用",
|
||||
} as Record<string, string>
|
||||
)[detail.order.status] || detail.order.status}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{detail.order.message}
|
||||
{codeStatus[detail.order.status]?.label || detail.order.status}
|
||||
</Typography>
|
||||
{detail.order.message && (
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{detail.order.message}
|
||||
</Typography>
|
||||
)}
|
||||
{detail.code ? (
|
||||
<>
|
||||
<TextField
|
||||
label="客户对应的完整卡密"
|
||||
label="客户对应的完整兑换码"
|
||||
multiline
|
||||
value={detail.code}
|
||||
slotProps={{ input: { readOnly: true } }}
|
||||
@@ -175,15 +191,16 @@ export function CustomerPanel({
|
||||
}}
|
||||
/>
|
||||
<Button variant="outlined" onClick={() => void copy()}>
|
||||
复制完整卡密
|
||||
复制完整兑换码
|
||||
</Button>
|
||||
</>
|
||||
) : (
|
||||
<Alert severity="info">
|
||||
此历史卡密仅保存了校验值,无法还原。仍可按此客户订单单独补单。
|
||||
此历史兑换码仅保存了校验值,无法还原完整内容。
|
||||
{detail.can_recover && "仍可按此客户订单单独补单。"}
|
||||
</Alert>
|
||||
)}
|
||||
{notice && <Alert severity="info">{notice}</Alert>}
|
||||
{notice && <Alert severity="info" role="status">{notice}</Alert>}
|
||||
{detail.checkout_url && (
|
||||
<>
|
||||
<TextField
|
||||
@@ -210,7 +227,7 @@ export function CustomerPanel({
|
||||
)}
|
||||
{detail.can_recover && (
|
||||
<Alert severity="info">
|
||||
“仅生成链接”不会付款;“单独补单”会先展示这一笔订单,确认后才尝试付款。
|
||||
「仅生成补单链接」不会付款;「单独补单」会先展示这一笔订单,确认后才尝试付款。
|
||||
</Alert>
|
||||
)}
|
||||
</Stack>
|
||||
|
||||
@@ -0,0 +1,169 @@
|
||||
import { useRef, useState } from "react";
|
||||
import {
|
||||
Alert,
|
||||
Box,
|
||||
Button,
|
||||
CircularProgress,
|
||||
InputAdornment,
|
||||
Paper,
|
||||
Stack,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import FactCheckRounded from "@mui/icons-material/FactCheckRounded";
|
||||
import { request } from "./shared";
|
||||
|
||||
// Standalone eligibility probe next to the redemption card: a visitor can
|
||||
// verify an X account before involving any redemption code. Advisory only.
|
||||
export function EligibilityCard() {
|
||||
const [username, setUsername] = useState("");
|
||||
const [checking, setChecking] = useState(false);
|
||||
const [invalid, setInvalid] = useState(false);
|
||||
const [result, setResult] = useState<{
|
||||
severity: "success" | "warning" | "info";
|
||||
message: string;
|
||||
} | null>(null);
|
||||
const field = useRef<HTMLInputElement>(null);
|
||||
const root = useRef<HTMLDivElement>(null);
|
||||
const alertRef = useRef<HTMLDivElement>(null);
|
||||
const cleanUser = username.trim().replace(/^@/, "").toLowerCase();
|
||||
const userValid = /^[a-z0-9_]{1,15}$/.test(cleanUser);
|
||||
|
||||
async function run() {
|
||||
setInvalid(!userValid);
|
||||
if (!userValid || checking) {
|
||||
if (!userValid) field.current?.focus();
|
||||
return;
|
||||
}
|
||||
// 检测期间输入框与按钮禁用,焦点会跌落;完成后泊放到结果提示。
|
||||
const refocus = root.current?.contains(document.activeElement) ?? false;
|
||||
setChecking(true);
|
||||
setResult(null);
|
||||
try {
|
||||
const { ok, data } = await request<{
|
||||
eligible?: boolean;
|
||||
message?: string;
|
||||
}>("/api/check", { username: cleanUser }, AbortSignal.timeout(45000));
|
||||
if (ok && typeof data.eligible === "boolean") {
|
||||
setResult(
|
||||
data.eligible
|
||||
? { severity: "success", message: "该账号当前可以接收赠送。" }
|
||||
: {
|
||||
severity: "warning",
|
||||
message: `该账号当前无法接收赠送:${data.message || "原因未知。"}`,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
setResult({
|
||||
severity: "info",
|
||||
message: data.message || "暂时无法检测,请稍后再试。",
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
setResult({ severity: "info", message: "暂时无法检测,请稍后再试。" });
|
||||
} finally {
|
||||
setChecking(false);
|
||||
// 仅当焦点确已跌落 body 时泊放;用户等待期间移走焦点不抢夺。
|
||||
if (refocus)
|
||||
requestAnimationFrame(() => {
|
||||
if (document.activeElement === document.body)
|
||||
alertRef.current?.focus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Paper
|
||||
ref={root}
|
||||
variant="outlined"
|
||||
component="section"
|
||||
aria-labelledby="eligibility-title"
|
||||
sx={{
|
||||
p: { xs: 2.5, sm: 4 },
|
||||
borderRadius: "28px",
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
}}
|
||||
>
|
||||
<Stack direction="row" spacing={1.5} alignItems="center" sx={{ mb: 1 }}>
|
||||
<FactCheckRounded color="primary" aria-hidden="true" />
|
||||
<Typography id="eligibility-title" component="h2" variant="h3">
|
||||
检测赠送资格
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 3 }}>
|
||||
兑换前先确认 X 账号当前能否接收 Premium 赠送。检测不消耗兑换码。
|
||||
</Typography>
|
||||
<Stack
|
||||
component="form"
|
||||
spacing={2.5}
|
||||
noValidate
|
||||
sx={{ flexGrow: 1 }}
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
void run();
|
||||
}}
|
||||
>
|
||||
<TextField
|
||||
label="X 用户名"
|
||||
value={username}
|
||||
onChange={(event) => {
|
||||
setUsername(event.target.value);
|
||||
setResult(null);
|
||||
if (invalid) setInvalid(false);
|
||||
}}
|
||||
disabled={checking}
|
||||
autoComplete="off"
|
||||
placeholder="your_username"
|
||||
error={invalid}
|
||||
helperText={
|
||||
invalid
|
||||
? "请输入 1–15 位英文字母、数字或下划线,不是显示名称。"
|
||||
: "填写 @ 后的用户名。"
|
||||
}
|
||||
slotProps={{
|
||||
htmlInput: {
|
||||
maxLength: 16,
|
||||
spellCheck: false,
|
||||
autoCapitalize: "none",
|
||||
ref: field,
|
||||
},
|
||||
input: {
|
||||
startAdornment: (
|
||||
<InputAdornment position="start">@</InputAdornment>
|
||||
),
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="outlined"
|
||||
size="large"
|
||||
disabled={checking}
|
||||
startIcon={
|
||||
checking ? (
|
||||
<CircularProgress size={18} aria-hidden="true" />
|
||||
) : undefined
|
||||
}
|
||||
>
|
||||
{checking ? "正在检测…" : "开始检测"}
|
||||
</Button>
|
||||
{result && (
|
||||
<Alert
|
||||
ref={alertRef}
|
||||
tabIndex={-1}
|
||||
severity={result.severity}
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
>
|
||||
{result.message}
|
||||
</Alert>
|
||||
)}
|
||||
<Box sx={{ flexGrow: 1 }} aria-hidden="true" />
|
||||
<Typography variant="caption" color="text.secondary" component="p">
|
||||
结果仅供参考,提交兑换时系统会向 X 再次核实。
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
+30
-28
@@ -152,7 +152,7 @@ function conditionLabel(token: Extract<Token, { kind: "condition" }>): string {
|
||||
const op = token.negate ? "≠" : ":";
|
||||
switch (token.field) {
|
||||
case "folder":
|
||||
return token.value === "-"
|
||||
return token.value === "-" && !token.literal
|
||||
? `批次${op}未分类`
|
||||
: `批次${op}${token.value}`;
|
||||
case "status":
|
||||
@@ -160,7 +160,7 @@ function conditionLabel(token: Extract<Token, { kind: "condition" }>): string {
|
||||
case "months":
|
||||
return `时长${op}${token.value} 个月`;
|
||||
case "username":
|
||||
return token.value === "-"
|
||||
return token.value === "-" && !token.literal
|
||||
? `账号${op}未绑定`
|
||||
: `账号${op}${token.value}`;
|
||||
}
|
||||
@@ -183,8 +183,15 @@ function tokenLabel(token: Token): string {
|
||||
}
|
||||
}
|
||||
|
||||
function quoteValue(name: string) {
|
||||
return /[\s()":=!≠]/.test(name) ? `"${name}"` : name;
|
||||
function quoteValue(name: string, literal = false) {
|
||||
// 批次名/账号可含任意字符;保留字、引号与反斜杠特殊处理,保证序列化结果
|
||||
// 可被 tokenizer 还原。哨兵值 "-"(未分类/未绑定)保持裸写;仅当名称本身
|
||||
// 就叫 "-" 时才加引号(literal,与 parse 的哨兵分支互逆)。
|
||||
if (/^(and|or|not|非|&&|\|\|)$/i.test(name) || (name === "-" && literal))
|
||||
return `"${name}"`;
|
||||
return /[\s()":=!≠\\:()!="“”]/.test(name)
|
||||
? `"${name.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/["“”]/g, "\\$&")}"`
|
||||
: name;
|
||||
}
|
||||
|
||||
function serializeTokens(tokens: Token[]): string {
|
||||
@@ -196,8 +203,8 @@ function serializeTokens(tokens: Token[]): string {
|
||||
case "condition": {
|
||||
const op = token.negate ? "!=" : ":";
|
||||
text =
|
||||
token.field === "folder"
|
||||
? `folder${op}${quoteValue(token.value)}`
|
||||
token.field === "folder" || token.field === "username"
|
||||
? `${token.field}${op}${quoteValue(token.value, token.literal)}`
|
||||
: `${token.field}${op}${token.value}`;
|
||||
break;
|
||||
}
|
||||
@@ -297,7 +304,10 @@ export function FilterBar({
|
||||
}: Props) {
|
||||
const [tokens, setTokens] = useState<Token[]>([]);
|
||||
const [mode, setMode] = useState<"palette" | "text">("palette");
|
||||
const [announce, setAnnounce] = useState("");
|
||||
// seq 递增保证相同文案重复播报时 live region 仍会重建触发朗读。
|
||||
const [announce, setAnnounce] = useState({ seq: 0, text: "" });
|
||||
const speak = (text: string) =>
|
||||
setAnnounce((current) => ({ seq: current.seq + 1, text }));
|
||||
const [desyncWarning, setDesyncWarning] = useState("");
|
||||
const [username, setUsername] = useState("");
|
||||
const canvasRef = useRef<HTMLDivElement>(null);
|
||||
@@ -312,7 +322,7 @@ export function FilterBar({
|
||||
// 文本无法解析:恢复为调色板内容并提示,保证画布与表达式永不脱节。
|
||||
const note = "无法解析文本表达式,已恢复为调色板中的条件。";
|
||||
setDesyncWarning(note);
|
||||
setAnnounce(note);
|
||||
speak(note);
|
||||
onChange(serializeTokens(tokens));
|
||||
}
|
||||
// tokens 刻意不作为依赖:只在 value / mode 变化时同步。
|
||||
@@ -328,7 +338,7 @@ export function FilterBar({
|
||||
useEffect(() => {
|
||||
if (applySeq > lastApplySeq.current) {
|
||||
lastApplySeq.current = applySeq;
|
||||
setAnnounce(
|
||||
speak(
|
||||
resultCount == null
|
||||
? "筛选已应用"
|
||||
: `筛选已应用,共 ${resultCount} 条结果`,
|
||||
@@ -340,14 +350,14 @@ export function FilterBar({
|
||||
lastNoticeSeq.current = clearNotice.seq;
|
||||
note = clearNotice.text;
|
||||
}
|
||||
setAnnounce(note);
|
||||
speak(note);
|
||||
}
|
||||
wasApplied.current = applied;
|
||||
}, [applied, applySeq, resultCount, clearNotice]);
|
||||
|
||||
function commit(next: Token[], note: string) {
|
||||
setTokens(next);
|
||||
setAnnounce(note);
|
||||
speak(note);
|
||||
setDesyncWarning("");
|
||||
onChange(serializeTokens(next));
|
||||
// 激活的调色板按钮可能在提交后被禁用,导致焦点跌回 <body>;
|
||||
@@ -402,17 +412,6 @@ export function FilterBar({
|
||||
commit(next, `已切换为 ${tokenLabel(updated)}`);
|
||||
}
|
||||
|
||||
// 条件 chip:Enter/Space(与点击一致)切换 = / ≠。
|
||||
function conditionChipKeyDown(index: number) {
|
||||
return (event: KeyboardEvent) => {
|
||||
if (disabled) return;
|
||||
if (event.key === "Enter" || event.key === " ") {
|
||||
event.preventDefault();
|
||||
toggleNegate(index);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 其他词元 chip 暴露 role="button",Enter/Space 与 Delete/Backspace 一样触发删除。
|
||||
function chipKeyDown(index: number) {
|
||||
return (event: KeyboardEvent) => {
|
||||
@@ -493,7 +492,7 @@ export function FilterBar({
|
||||
sx={{ mb: 0.5, flexWrap: "wrap", rowGap: 0.5 }}
|
||||
>
|
||||
<FilterAltOutlined color="primary" sx={{ flexShrink: 0 }} />
|
||||
<Typography variant="h3" sx={{ whiteSpace: "nowrap", flexShrink: 0 }}>
|
||||
<Typography variant="h2" sx={{ whiteSpace: "nowrap", flexShrink: 0, fontSize: 21 }}>
|
||||
高级筛选
|
||||
</Typography>
|
||||
{applied && (
|
||||
@@ -511,7 +510,6 @@ export function FilterBar({
|
||||
variant="text"
|
||||
size="small"
|
||||
startIcon={mode === "palette" ? <CodeOutlined /> : <PaletteOutlined />}
|
||||
aria-pressed={mode === "text"}
|
||||
aria-label={
|
||||
mode === "palette" ? "切换到文本模式" : "切换到调色板模式"
|
||||
}
|
||||
@@ -567,7 +565,7 @@ export function FilterBar({
|
||||
event.preventDefault();
|
||||
if (!applyDisabled) onApply();
|
||||
// 表达式无效时 Enter 不再静默,播报当前不可应用的原因。
|
||||
else if (invalidReason) setAnnounce(invalidReason);
|
||||
else if (invalidReason) speak(invalidReason);
|
||||
}
|
||||
}}
|
||||
sx={(theme) => ({
|
||||
@@ -617,7 +615,6 @@ export function FilterBar({
|
||||
aria-label={`${tokenLabel(token)},按 Enter 或点击切换 = / ≠,按 Delete 或 Backspace 删除`}
|
||||
onClick={disabled ? undefined : () => toggleNegate(index)}
|
||||
onDelete={disabled ? undefined : () => removeAt(index)}
|
||||
onKeyDown={conditionChipKeyDown(index)}
|
||||
sx={[
|
||||
chipSizeSx,
|
||||
conditionTint(tokenTone(token)),
|
||||
@@ -727,6 +724,8 @@ export function FilterBar({
|
||||
field: "folder",
|
||||
value: folder.name,
|
||||
negate: false,
|
||||
// 批次名恰为哨兵值 "-" 时保持字法语义。
|
||||
literal: folder.name === "-" ? true : undefined,
|
||||
})
|
||||
}
|
||||
ariaLabel={`添加批次条件 ${folder.name}`}
|
||||
@@ -805,7 +804,9 @@ export function FilterBar({
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter") {
|
||||
event.preventDefault();
|
||||
addUsername();
|
||||
if (username.trim() && !usernameValid)
|
||||
speak("账号名需为字母、数字或下划线。");
|
||||
else addUsername();
|
||||
}
|
||||
}}
|
||||
slotProps={{
|
||||
@@ -984,11 +985,12 @@ export function FilterBar({
|
||||
</Stack>
|
||||
<Box
|
||||
component="span"
|
||||
key={announce.seq}
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
sx={visuallyHidden}
|
||||
>
|
||||
{announce}
|
||||
{announce.text}
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
|
||||
@@ -22,17 +22,15 @@ type Props = {
|
||||
stats?: AdminStats;
|
||||
filter: string;
|
||||
disabled: boolean;
|
||||
muted?: boolean;
|
||||
onSelect: (id: string) => void;
|
||||
onBusyChange: (value: boolean) => void;
|
||||
onChanged: (deleted?: string) => Promise<void>;
|
||||
onChanged: () => Promise<void>;
|
||||
};
|
||||
export function FolderPanel({
|
||||
folders,
|
||||
stats,
|
||||
filter,
|
||||
disabled,
|
||||
muted = false,
|
||||
onSelect,
|
||||
onBusyChange,
|
||||
onChanged,
|
||||
@@ -84,12 +82,10 @@ export function FolderPanel({
|
||||
useFlexGap
|
||||
gap={1}
|
||||
sx={{
|
||||
height: 80,
|
||||
minHeight: 80,
|
||||
overflowX: "auto",
|
||||
alignItems: "center",
|
||||
pb: 1,
|
||||
opacity: muted ? 0.55 : 1,
|
||||
transition: "opacity 160ms ease",
|
||||
}}
|
||||
role="region"
|
||||
aria-label="批次文件夹,可横向滚动"
|
||||
@@ -164,28 +160,34 @@ export function FolderPanel({
|
||||
fullWidth
|
||||
maxWidth="xs"
|
||||
aria-labelledby="batch-rename-title"
|
||||
aria-describedby="batch-rename-content"
|
||||
>
|
||||
<Box
|
||||
component="form"
|
||||
noValidate
|
||||
onSubmit={(e) => {
|
||||
e.preventDefault();
|
||||
void save();
|
||||
}}
|
||||
>
|
||||
<DialogTitle id="batch-rename-title">重命名批次</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContent id="batch-rename-content">
|
||||
<TextField
|
||||
autoFocus
|
||||
label="批次名称"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
onChange={(e) => {
|
||||
setName(e.target.value);
|
||||
if (error) setError("");
|
||||
}}
|
||||
disabled={pending}
|
||||
required
|
||||
error={!!error}
|
||||
sx={{ mt: 1 }}
|
||||
helperText="该批次内的兑换码会同步更新名称"
|
||||
/>
|
||||
{error && (
|
||||
<Alert severity="error" sx={{ mt: 2 }}>
|
||||
<Alert severity="error" role="alert" sx={{ mt: 2 }}>
|
||||
{error}
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,281 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
Alert,
|
||||
Box,
|
||||
Button,
|
||||
Chip,
|
||||
CircularProgress,
|
||||
Paper,
|
||||
Stack,
|
||||
TextField,
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import ManageSearchRounded from "@mui/icons-material/ManageSearchRounded";
|
||||
import { adminApi, formatTime, type AdminCode } from "./adminApi";
|
||||
import { codeStatus } from "./codeStatus";
|
||||
|
||||
// Direct lookup by full redemption code: status, batch and recipient without
|
||||
// paging through folders. Actions delegate to the parent's existing flows.
|
||||
export function LookupPanel({
|
||||
disabled,
|
||||
refreshSignal,
|
||||
onCopy,
|
||||
onViewCustomer,
|
||||
onRevoke,
|
||||
}: {
|
||||
disabled: boolean;
|
||||
refreshSignal: number;
|
||||
onCopy: (code: AdminCode) => void;
|
||||
onViewCustomer: (id: string) => void;
|
||||
onRevoke: (code: AdminCode) => void;
|
||||
}) {
|
||||
const [input, setInput] = useState("");
|
||||
const [busy, setBusy] = useState(false);
|
||||
const [invalid, setInvalid] = useState(false);
|
||||
const [error, setError] = useState("");
|
||||
const [result, setResult] = useState<AdminCode | null>(null);
|
||||
const queried = useRef("");
|
||||
const sequence = useRef(0);
|
||||
const field = useRef<HTMLInputElement>(null);
|
||||
const clean = input.replace(/\s+/g, "").toUpperCase();
|
||||
const valid = /^XG-[A-F0-9]{48}$/.test(clean);
|
||||
|
||||
async function run(code: string) {
|
||||
const seq = ++sequence.current;
|
||||
setBusy(true);
|
||||
setError("");
|
||||
try {
|
||||
const data = await adminApi<AdminCode>("/api/admin/lookup", { code });
|
||||
if (seq === sequence.current) {
|
||||
setResult(data);
|
||||
queried.current = code;
|
||||
}
|
||||
} catch (e) {
|
||||
if (seq === sequence.current) {
|
||||
setResult(null);
|
||||
setError((e as Error).message);
|
||||
}
|
||||
} finally {
|
||||
if (seq === sequence.current) setBusy(false);
|
||||
}
|
||||
}
|
||||
function submit() {
|
||||
setInvalid(!valid);
|
||||
if (!valid || busy || disabled) {
|
||||
if (!valid) field.current?.focus();
|
||||
return;
|
||||
}
|
||||
void run(clean);
|
||||
}
|
||||
// Keep a visible result in sync after mutations (revoke, move, folder ops).
|
||||
// Only while the shown result still matches the input: once the admin edits
|
||||
// the field, the old result is gone and must not reappear.
|
||||
useEffect(() => {
|
||||
if (refreshSignal > 0 && result && queried.current === clean)
|
||||
void run(queried.current);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [refreshSignal]);
|
||||
|
||||
const rows = result
|
||||
? [
|
||||
["接收账号", result.username ? `@${result.username}` : "—"],
|
||||
["批次", result.batch || "未分类"],
|
||||
[
|
||||
"生成时间",
|
||||
formatTime(result.created),
|
||||
],
|
||||
...(result.status === "processing" || result.status === "review"
|
||||
? [["订单进度", `${Math.min(100, Math.max(0, result.progress ?? 0))}%`]]
|
||||
: []),
|
||||
]
|
||||
: [];
|
||||
|
||||
return (
|
||||
<Paper
|
||||
variant="outlined"
|
||||
component="section"
|
||||
aria-labelledby="lookup-title"
|
||||
sx={{ p: { xs: 2, sm: 3 }, height: "100%" }}
|
||||
>
|
||||
<Stack direction="row" spacing={1} alignItems="center">
|
||||
<ManageSearchRounded color="primary" aria-hidden="true" />
|
||||
<Typography id="lookup-title" variant="h2" sx={{ fontSize: 21 }}>
|
||||
按兑换码查询
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Box
|
||||
component="form"
|
||||
noValidate
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
submit();
|
||||
}}
|
||||
sx={{ mt: 2 }}
|
||||
>
|
||||
<Stack direction={{ xs: "column", sm: "row" }} spacing={1}>
|
||||
<TextField
|
||||
label="完整兑换码"
|
||||
placeholder="XG-…"
|
||||
value={input}
|
||||
onChange={(event) => {
|
||||
// 编辑即作废在途响应:旧结果不得在输入变化后重新出现。
|
||||
sequence.current++;
|
||||
setInput(event.target.value);
|
||||
setResult(null);
|
||||
setError("");
|
||||
if (invalid) setInvalid(false);
|
||||
}}
|
||||
size="small"
|
||||
fullWidth
|
||||
autoComplete="off"
|
||||
error={invalid}
|
||||
helperText={
|
||||
invalid
|
||||
? "请输入 XG- 开头、后接 48 位十六进制字符(0-9、A-F)的完整兑换码。"
|
||||
: " "
|
||||
}
|
||||
slotProps={{
|
||||
htmlInput: { maxLength: 80, spellCheck: false, ref: field },
|
||||
input: { sx: { fontFamily: "monospace", fontSize: 16 } },
|
||||
}}
|
||||
/>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="outlined"
|
||||
disabled={busy || disabled || !input.trim()}
|
||||
startIcon={
|
||||
busy ? <CircularProgress size={16} aria-hidden="true" /> : undefined
|
||||
}
|
||||
sx={{ whiteSpace: "nowrap", alignSelf: { sm: "flex-start" } }}
|
||||
>
|
||||
{busy ? "正在查询…" : "查询兑换码"}
|
||||
</Button>
|
||||
</Stack>
|
||||
</Box>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
粘贴客户提供的完整兑换码,直接查看状态、批次和接收账号,无需按批次翻页。
|
||||
</Typography>
|
||||
{error && (
|
||||
<Alert severity="error" role="alert" sx={{ mt: 2 }}>
|
||||
{error}
|
||||
</Alert>
|
||||
)}
|
||||
<Box aria-live="polite">
|
||||
{result && (
|
||||
<Box
|
||||
sx={{
|
||||
mt: 2,
|
||||
p: 2,
|
||||
border: 1,
|
||||
borderColor: "divider",
|
||||
borderRadius: 2,
|
||||
bgcolor: "background.default",
|
||||
}}
|
||||
>
|
||||
<Stack
|
||||
direction="row"
|
||||
spacing={1}
|
||||
alignItems="center"
|
||||
flexWrap="wrap"
|
||||
useFlexGap
|
||||
>
|
||||
<Chip
|
||||
size="small"
|
||||
variant="outlined"
|
||||
color={codeStatus[result.status]?.color ?? "default"}
|
||||
label={codeStatus[result.status]?.label ?? result.status}
|
||||
/>
|
||||
<Typography variant="body2" fontWeight={600}>
|
||||
{result.months} 个月
|
||||
</Typography>
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
sx={{ fontFamily: "monospace" }}
|
||||
>
|
||||
尾号 …{result.hint}
|
||||
</Typography>
|
||||
</Stack>
|
||||
<Box
|
||||
component="dl"
|
||||
sx={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: "auto 1fr",
|
||||
columnGap: 2,
|
||||
rowGap: 0.5,
|
||||
m: 0,
|
||||
mt: 1.5,
|
||||
}}
|
||||
>
|
||||
{rows.map(([label, value]) => (
|
||||
<Box component="div" key={label} sx={{ display: "contents" }}>
|
||||
<Typography
|
||||
component="dt"
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
sx={{ whiteSpace: "nowrap" }}
|
||||
>
|
||||
{label}
|
||||
</Typography>
|
||||
<Typography
|
||||
component="dd"
|
||||
variant="body2"
|
||||
sx={{ m: 0, overflowWrap: "anywhere" }}
|
||||
>
|
||||
{value}
|
||||
</Typography>
|
||||
</Box>
|
||||
))}
|
||||
</Box>
|
||||
{result.message && (
|
||||
<Typography
|
||||
variant="body2"
|
||||
color="text.secondary"
|
||||
sx={{ mt: 1, overflowWrap: "anywhere" }}
|
||||
>
|
||||
{result.message}
|
||||
</Typography>
|
||||
)}
|
||||
<Stack
|
||||
direction="row"
|
||||
spacing={1}
|
||||
flexWrap="wrap"
|
||||
useFlexGap
|
||||
sx={{ mt: 1.5 }}
|
||||
>
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
disabled={disabled}
|
||||
onClick={() => onViewCustomer(result.id)}
|
||||
>
|
||||
查看兑换码 / 补单
|
||||
</Button>
|
||||
{result.copyable && (
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
disabled={disabled}
|
||||
onClick={() => onCopy(result)}
|
||||
>
|
||||
复制完整兑换码
|
||||
</Button>
|
||||
)}
|
||||
{result.status === "active" && (
|
||||
<Button
|
||||
size="small"
|
||||
variant="outlined"
|
||||
color="error"
|
||||
disabled={disabled}
|
||||
onClick={() => onRevoke(result)}
|
||||
>
|
||||
停用
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
</Paper>
|
||||
);
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import {
|
||||
Typography,
|
||||
} from "@mui/material";
|
||||
import ExpandMoreRounded from "@mui/icons-material/ExpandMoreRounded";
|
||||
import { adminApi } from "./adminApi";
|
||||
import { adminApi, formatTime } from "./adminApi";
|
||||
import type { RecoverySelection } from "./CustomerPanel";
|
||||
|
||||
type Item = {
|
||||
@@ -47,6 +47,7 @@ type Batch = {
|
||||
created: number;
|
||||
updated?: number;
|
||||
last4: string;
|
||||
cards?: number;
|
||||
paused: boolean;
|
||||
message: string;
|
||||
items: Item[];
|
||||
@@ -83,13 +84,13 @@ function resultSummary(items: Item[]) {
|
||||
return [`共 ${items.length} 笔`, ...parts.filter(([, n]) => n > 0).map(([label, n]) => `${label} ${n} 笔`)].join(" · ");
|
||||
}
|
||||
function taskTime(seconds?: number) {
|
||||
return seconds ? new Date(seconds * 1000).toLocaleString("zh-CN", { hour12: false }) : "时间未记录";
|
||||
return seconds ? formatTime(seconds) : "时间未记录";
|
||||
}
|
||||
function BatchDetails({ batch }: { batch: Batch }) {
|
||||
return <>
|
||||
<Stack direction="row" flexWrap="wrap" gap={1} alignItems="center">
|
||||
<Chip size="small" label={labels[batch.state] || batch.state} />
|
||||
<Typography variant="body2">{batch.mode === "links" ? "仅生成链接" : `付款卡尾号 ${batch.last4}`} · {resultSummary(batch.items)}</Typography>
|
||||
<Typography variant="body2">{batch.mode === "links" ? "仅生成补单链接" : batch.cards && batch.cards > 1 ? `付款卡 ${batch.cards} 张随机轮换(当前尾号 ${batch.last4})` : `付款卡尾号 ${batch.last4}`} · {resultSummary(batch.items)}</Typography>
|
||||
</Stack>
|
||||
<Typography variant="caption" color="text.secondary" display="block" sx={{ mt: 1 }}>
|
||||
创建于 {taskTime(batch.created)} · 更新于 {taskTime(batch.updated || batch.created)}
|
||||
@@ -123,7 +124,7 @@ function Orders({ items }: { items: Item[] }) {
|
||||
fontWeight={600}
|
||||
sx={{ overflowWrap: "anywhere" }}
|
||||
>
|
||||
@{item.username} · 卡密尾号 {item.hint}
|
||||
@{item.username} · 兑换码尾号 {item.hint}
|
||||
</Typography>
|
||||
{item.payment_node && (
|
||||
<Typography variant="caption">付款节点 {item.payment_node}</Typography>
|
||||
@@ -157,6 +158,9 @@ function Orders({ items }: { items: Item[] }) {
|
||||
))}
|
||||
</Stack>
|
||||
<TableContainer
|
||||
tabIndex={0}
|
||||
role="region"
|
||||
aria-label="补单订单清单,可滚动查看"
|
||||
sx={{ maxHeight: 380, display: { xs: "none", sm: "block" } }}
|
||||
>
|
||||
<Table size="small" stickyHeader aria-label="补单订单清单">
|
||||
@@ -173,7 +177,7 @@ function Orders({ items }: { items: Item[] }) {
|
||||
<TableCell sx={{ verticalAlign: "top", minWidth: 140 }}>
|
||||
<Typography variant="body2">@{item.username}</Typography>
|
||||
<Typography variant="caption" display="block">
|
||||
卡密尾号 {item.hint}
|
||||
兑换码尾号 {item.hint}
|
||||
{item.payment_node && ` · 付款节点 ${item.payment_node}`}
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
@@ -232,6 +236,8 @@ export function RecoveryPanel({
|
||||
const linksOnly = batch?.mode === "links";
|
||||
const mutating = useRef(false);
|
||||
const sequence = useRef(0);
|
||||
// 上一个补单操作在途时到达的 selection 先暂存,完成后补发,避免"点了没反应"。
|
||||
const pendingSelection = useRef<RecoverySelection | null>(null);
|
||||
const active = batch?.state === "running" || batch?.state === "stopping";
|
||||
const pending =
|
||||
batch?.items.filter((item) => item.state === "pending").length || 0;
|
||||
@@ -264,7 +270,10 @@ export function RecoveryPanel({
|
||||
};
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
if (selection) void act("preview", selection);
|
||||
if (selection) {
|
||||
if (mutating.current) pendingSelection.current = selection;
|
||||
else void act("preview", selection);
|
||||
}
|
||||
}, [selection]);
|
||||
async function act(
|
||||
action: "preview" | "start" | "stop",
|
||||
@@ -303,6 +312,11 @@ export function RecoveryPanel({
|
||||
mutating.current = false;
|
||||
sequence.current++;
|
||||
setBusy(false);
|
||||
const queued = pendingSelection.current;
|
||||
if (queued) {
|
||||
pendingSelection.current = null;
|
||||
void act("preview", queued);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (
|
||||
@@ -341,7 +355,7 @@ export function RecoveryPanel({
|
||||
disabled={busy || active}
|
||||
onClick={() => void act("preview", { mode: "links" })}
|
||||
>
|
||||
仅生成链接
|
||||
仅生成补单链接
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
@@ -363,20 +377,20 @@ export function RecoveryPanel({
|
||||
</Stack>
|
||||
</Stack>
|
||||
{error && !open && (
|
||||
<Alert severity="error" sx={{ mt: 2 }}>
|
||||
<Alert severity="error" role="alert" sx={{ mt: 2 }}>
|
||||
{error}
|
||||
</Alert>
|
||||
)}
|
||||
{statusError && <Alert severity="error" sx={{ mt: 2 }}>当前状态读取失败:{statusError}</Alert>}
|
||||
<Box sx={{ mt: 2 }} aria-live="polite">
|
||||
<Typography variant="body2" fontWeight={600}>
|
||||
{statusError && <Alert severity="error" role="alert" sx={{ mt: 2 }}>当前状态读取失败:{statusError}</Alert>}
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<Typography variant="body2" fontWeight={600} aria-live="polite">
|
||||
{statusError ? "当前状态暂不可用" : active ? "当前有补单任务运行中" : summary ? "当前没有运行中的补单任务" : "正在读取当前状态…"}
|
||||
</Typography>
|
||||
{summary && <Typography variant="body2" color="text.secondary" sx={{ mt: 0.5 }}>
|
||||
当前订单:待核实 {summary.review} 笔 · 充值处理中 {summary.processing} 笔
|
||||
</Typography>}
|
||||
</Box>
|
||||
{batch && active && (
|
||||
{batch && active && !statusError && (
|
||||
<Box sx={{ mt: 2 }}>
|
||||
<BatchDetails batch={batch} />
|
||||
</Box>
|
||||
@@ -393,7 +407,7 @@ export function RecoveryPanel({
|
||||
</Typography>
|
||||
</Box>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails>
|
||||
<AccordionDetails id="recovery-history-content">
|
||||
<Typography variant="body2" color="text.secondary" sx={{ mb: 1.5 }}>
|
||||
以下为这次任务保存的处理结果。当前订单数量显示在上方;刷新页面不会重新执行此任务。
|
||||
</Typography>
|
||||
@@ -417,13 +431,14 @@ export function RecoveryPanel({
|
||||
},
|
||||
}}
|
||||
aria-labelledby="recovery-title"
|
||||
aria-describedby="recovery-dialog-description"
|
||||
>
|
||||
<DialogTitle id="recovery-title">
|
||||
{linksOnly ? "确认生成补单链接(不付款)" : "确认手动补单"}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContent id="recovery-dialog-description">
|
||||
{error && (
|
||||
<Alert severity="error" sx={{ mb: 2 }}>
|
||||
<Alert severity="error" role="alert" sx={{ mb: 2 }}>
|
||||
{error}
|
||||
</Alert>
|
||||
)}
|
||||
@@ -432,7 +447,7 @@ export function RecoveryPanel({
|
||||
"只生成或更新付款链接,不提交银行卡付款;核验并处理"
|
||||
) : (
|
||||
<>
|
||||
使用银行卡尾号 <strong>{batch?.last4}</strong>,核验并处理
|
||||
{batch?.cards && batch.cards > 1 ? <>使用 <strong>{batch.cards}</strong> 张银行卡随机轮换(当前尾号 <strong>{batch?.last4}</strong>)</> : <>使用银行卡尾号 <strong>{batch?.last4}</strong></>},核验并处理
|
||||
</>
|
||||
)}{" "}
|
||||
<strong>{pending}</strong> 笔订单,账单总额{" "}
|
||||
@@ -478,7 +493,7 @@ export function RecoveryPanel({
|
||||
}
|
||||
label={
|
||||
linksOnly
|
||||
? "我已核对客户和套餐,确认仅生成链接,不付款。"
|
||||
? "我已核对客户和套餐,确认仅生成补单链接,不付款。"
|
||||
: "我已核对客户、套餐、账单金额和银行卡,确认启动本批次付款。"
|
||||
}
|
||||
/>
|
||||
|
||||
+15
-10
@@ -18,10 +18,10 @@ import { stats as fetchStats, type AdminStatsDetail } from "./adminApi";
|
||||
|
||||
const visuallyHidden = {
|
||||
position: "absolute",
|
||||
width: 1,
|
||||
height: 1,
|
||||
width: "1px",
|
||||
height: "1px",
|
||||
p: 0,
|
||||
m: -1,
|
||||
m: "-1px",
|
||||
overflow: "hidden",
|
||||
clip: "rect(0 0 0 0)",
|
||||
whiteSpace: "nowrap",
|
||||
@@ -241,7 +241,8 @@ export function StatsPanel({ refreshSignal }: { refreshSignal: number }) {
|
||||
1,
|
||||
...(data?.review_stages ?? []).map((stage) => stage.count),
|
||||
);
|
||||
const remainder = theme.vars.palette.primary.light;
|
||||
// Neutral track color that stays calm on dark surfaces (primary.light does not).
|
||||
const remainder = theme.vars.palette.divider;
|
||||
return (
|
||||
<Paper variant="outlined" sx={{ mb: 3, overflow: "hidden" }}>
|
||||
<Button
|
||||
@@ -282,8 +283,12 @@ export function StatsPanel({ refreshSignal }: { refreshSignal: number }) {
|
||||
aria-label="统计概览"
|
||||
sx={{ px: { xs: 2.5, sm: 3 }, pb: 3, pt: 1 }}
|
||||
>
|
||||
{/* 折叠按钮内的标题是 span,补一个隐藏的 h2 让小节 h3 有父级。 */}
|
||||
<Typography variant="h2" sx={visuallyHidden}>
|
||||
统计概览
|
||||
</Typography>
|
||||
{loading && (
|
||||
<Stack spacing={2} aria-label="正在加载统计数据">
|
||||
<Stack spacing={2} role="status" aria-label="正在加载统计数据">
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
@@ -302,7 +307,7 @@ export function StatsPanel({ refreshSignal }: { refreshSignal: number }) {
|
||||
</Stack>
|
||||
)}
|
||||
{!loading && error && (
|
||||
<Alert severity="error">
|
||||
<Alert severity="error" role="alert">
|
||||
{error}
|
||||
{data && " 以下保留上次加载的数据。"}
|
||||
<Button onClick={() => void load()}>重新加载</Button>
|
||||
@@ -336,9 +341,9 @@ export function StatsPanel({ refreshSignal }: { refreshSignal: number }) {
|
||||
value={String(data.codes.succeeded)}
|
||||
hint={`成功率 ${successRate}`}
|
||||
/>
|
||||
<StatCard label="待处理" value={String(data.codes.processing)} />
|
||||
<StatCard label="待审核" value={String(data.codes.review)} />
|
||||
<StatCard label="已撤销" value={String(data.codes.revoked)} />
|
||||
<StatCard label="处理中" value={String(data.codes.processing)} />
|
||||
<StatCard label="待核实" value={String(data.codes.review)} />
|
||||
<StatCard label="已停用" value={String(data.codes.revoked)} />
|
||||
</Box>
|
||||
{data.daily.length > 0 && (
|
||||
<Box component="section" aria-labelledby="stats-daily-title">
|
||||
@@ -445,7 +450,7 @@ export function StatsPanel({ refreshSignal }: { refreshSignal: number }) {
|
||||
{data.review_stages.length > 0 && (
|
||||
<Box component="section" aria-labelledby="stats-stages-title">
|
||||
<Typography id="stats-stages-title" variant="h3" sx={{ mb: 1.5 }}>
|
||||
待审核阶段分布
|
||||
待核实阶段分布
|
||||
</Typography>
|
||||
<Stack spacing={1.5}>
|
||||
{[...data.review_stages]
|
||||
|
||||
+102
-62
@@ -36,26 +36,23 @@ import ConfirmationNumberOutlined from "@mui/icons-material/ConfirmationNumberOu
|
||||
import { mount, Shell } from "./shared";
|
||||
import { AppearanceMenu } from "./AppearanceMenu";
|
||||
import { CopyableCodes } from "./CopyableCodes";
|
||||
import { adminApi as api, type AdminStats, type Folder } from "./adminApi";
|
||||
import {
|
||||
adminApi as api,
|
||||
formatTime,
|
||||
type AdminCode,
|
||||
type AdminStats,
|
||||
type Folder,
|
||||
} from "./adminApi";
|
||||
import { codeStatus as statuses } from "./codeStatus";
|
||||
import { FolderPanel } from "./FolderPanel";
|
||||
import { FilterBar } from "./FilterBar";
|
||||
import { parseFilter } from "./filter";
|
||||
import { CustomerPanel, type RecoverySelection } from "./CustomerPanel";
|
||||
import { LookupPanel } from "./LookupPanel";
|
||||
import { RecoveryPanel } from "./RecoveryPanel";
|
||||
import { StatsPanel } from "./StatsPanel";
|
||||
|
||||
type Code = {
|
||||
copyable: boolean;
|
||||
folder: string;
|
||||
id: string;
|
||||
hint: string;
|
||||
batch: string;
|
||||
months: number;
|
||||
status: string;
|
||||
username: string;
|
||||
message: string;
|
||||
created: number;
|
||||
};
|
||||
type Code = AdminCode;
|
||||
type Listing = {
|
||||
folder: string;
|
||||
folders: Folder[];
|
||||
@@ -72,16 +69,6 @@ type Generated = {
|
||||
folder: string;
|
||||
};
|
||||
type Confirmation = { kind: "revoke"; code: Code } | null;
|
||||
const statuses: Record<
|
||||
string,
|
||||
{ label: string; color: "default" | "primary" | "success" | "warning" }
|
||||
> = {
|
||||
active: { label: "可使用", color: "primary" },
|
||||
processing: { label: "处理中", color: "primary" },
|
||||
succeeded: { label: "已完成", color: "success" },
|
||||
review: { label: "待核实", color: "warning" },
|
||||
revoked: { label: "已停用", color: "default" },
|
||||
};
|
||||
function Admin() {
|
||||
const [customerSelection, setCustomerSelection] = useState<{
|
||||
id: string;
|
||||
@@ -97,6 +84,8 @@ function Admin() {
|
||||
const [count, setCount] = useState("10");
|
||||
const [batch, setBatch] = useState("");
|
||||
const [copyNotice, setCopyNotice] = useState("");
|
||||
// 连续复制时重置 Snackbar 的自动隐藏计时,避免第二条提示一闪而过。
|
||||
const [copySeq, setCopySeq] = useState(0);
|
||||
const copying = useRef(false);
|
||||
const [selectedIDs, setSelectedIDs] = useState<string[]>([]);
|
||||
const [moveOpen, setMoveOpen] = useState(false);
|
||||
@@ -121,7 +110,7 @@ function Admin() {
|
||||
const [confirmation, setConfirmation] = useState<Confirmation>(null);
|
||||
const [batchError, setBatchError] = useState(false);
|
||||
const [countError, setCountError] = useState(false);
|
||||
const [focusTarget, setFocusTarget] = useState<"form" | "list" | null>(null);
|
||||
const [focusTarget, setFocusTarget] = useState<"list" | null>(null);
|
||||
const [statsSignal, setStatsSignal] = useState(0);
|
||||
const listSequence = useRef(0);
|
||||
const mutation = useRef(false);
|
||||
@@ -131,6 +120,8 @@ function Admin() {
|
||||
const refresh = useCallback(
|
||||
async (page: number, folder = filterRef.current) => {
|
||||
const sequence = ++listSequence.current;
|
||||
// 跨页翻页保留选择;只有切换批次时才清空(筛选模式的进出单独管理)。
|
||||
const switchingFolder = folder !== filterRef.current;
|
||||
setLoading(true);
|
||||
setListError("");
|
||||
try {
|
||||
@@ -140,7 +131,7 @@ function Admin() {
|
||||
if (sequence === listSequence.current) {
|
||||
setListing(data);
|
||||
filterRef.current = data.folder;
|
||||
setSelectedIDs([]);
|
||||
if (switchingFolder) setSelectedIDs([]);
|
||||
// The panel fetches on mount; only nudge it for later refreshes.
|
||||
if (sequence > 1) setStatsSignal((value) => value + 1);
|
||||
}
|
||||
@@ -160,7 +151,7 @@ function Admin() {
|
||||
// Filter mode: parse the expression, fetch every page client-side, then
|
||||
// evaluate the predicate locally. Shares listSequence with refresh() so
|
||||
// overlapping loads from either mode cancel each other.
|
||||
const applyFilter = useCallback(async (source: string) => {
|
||||
const applyFilter = useCallback(async (source: string, keepPage = false) => {
|
||||
let match: (code: Code) => boolean;
|
||||
try {
|
||||
match = parseFilter(source);
|
||||
@@ -185,7 +176,7 @@ function Admin() {
|
||||
setAllCodes(codes);
|
||||
setActiveFilter({ source, match });
|
||||
setApplySeq((value) => value + 1);
|
||||
setFilterPage(0);
|
||||
if (!keepPage) setFilterPage(0);
|
||||
setSelectedIDs([]);
|
||||
} catch (error) {
|
||||
if (sequence === listSequence.current)
|
||||
@@ -202,12 +193,18 @@ function Admin() {
|
||||
setFilterError("");
|
||||
setFilterPage(0);
|
||||
setSelectedIDs([]);
|
||||
if (reload) void refresh(0);
|
||||
if (reload) void refresh(0, "");
|
||||
}
|
||||
|
||||
// After any mutation, reload the current view and keep stats/lookup panels
|
||||
// in sync (applyFilter does not touch statsSignal on its own; refresh does).
|
||||
function reloadCurrent() {
|
||||
if (activeFilter) void applyFilter(activeFilter.source);
|
||||
else void refresh(listing?.page ?? 0);
|
||||
if (activeFilter) {
|
||||
void applyFilter(activeFilter.source, true);
|
||||
setStatsSignal((value) => value + 1);
|
||||
} else {
|
||||
void refresh(listing?.page ?? 0);
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@@ -215,7 +212,6 @@ function Admin() {
|
||||
// Restore to a surviving control after the dialog's exit transition.
|
||||
const timer = setTimeout(() => {
|
||||
if (focusTarget === "list") refreshButton.current?.focus();
|
||||
else form.current?.querySelector<HTMLElement>("[role=combobox]")?.focus();
|
||||
setFocusTarget(null);
|
||||
}, 250);
|
||||
return () => clearTimeout(timer);
|
||||
@@ -224,6 +220,7 @@ function Admin() {
|
||||
async function copyRow(code: Code) {
|
||||
if (!code.copyable) {
|
||||
setCopyNotice("历史兑换码未保存完整内容,请使用原先下载的 TXT。");
|
||||
setCopySeq((value) => value + 1);
|
||||
return;
|
||||
}
|
||||
if (copying.current) return;
|
||||
@@ -248,6 +245,7 @@ function Admin() {
|
||||
} catch {
|
||||
setCopyNotice("复制失败,请检查剪贴板权限或稍后重试。");
|
||||
} finally {
|
||||
setCopySeq((value) => value + 1);
|
||||
copying.current = false;
|
||||
}
|
||||
}
|
||||
@@ -290,6 +288,7 @@ function Admin() {
|
||||
try {
|
||||
await api("/api/admin/revoke", { id: confirmation.code.id });
|
||||
setNotice({ text: "兑换码已停用。", error: false });
|
||||
setSelectedIDs([]);
|
||||
setFocusTarget("list");
|
||||
setConfirmation(null);
|
||||
reloadCurrent();
|
||||
@@ -315,6 +314,7 @@ function Admin() {
|
||||
text: `已移动 ${selectedIDs.length} 枚兑换码。`,
|
||||
error: false,
|
||||
});
|
||||
setSelectedIDs([]);
|
||||
setMoveOpen(false);
|
||||
setFocusTarget("list");
|
||||
reloadCurrent();
|
||||
@@ -351,6 +351,8 @@ function Admin() {
|
||||
const visibleCodes = matched
|
||||
? matched.slice(safeFilterPage * 100, safeFilterPage * 100 + 100)
|
||||
: (listing?.codes ?? []);
|
||||
const pageIDs = visibleCodes.map((code) => code.id);
|
||||
const pageSelected = pageIDs.filter((id) => selectedIDs.includes(id));
|
||||
|
||||
return (
|
||||
<Shell admin>
|
||||
@@ -387,12 +389,32 @@ function Admin() {
|
||||
<AppearanceMenu />
|
||||
</Stack>
|
||||
</Stack>
|
||||
<CustomerPanel
|
||||
selected={customerSelection}
|
||||
onPrepare={(id, mode) =>
|
||||
setRecoverySelection({ id, mode, seq: Date.now() })
|
||||
}
|
||||
/>
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: {
|
||||
xs: "1fr",
|
||||
md: "minmax(0, 1fr) minmax(0, 1fr)",
|
||||
},
|
||||
gap: 3,
|
||||
mb: 3,
|
||||
alignItems: "stretch",
|
||||
}}
|
||||
>
|
||||
<CustomerPanel
|
||||
selected={customerSelection}
|
||||
onPrepare={(id, mode) =>
|
||||
setRecoverySelection({ id, mode, seq: Date.now() })
|
||||
}
|
||||
/>
|
||||
<LookupPanel
|
||||
disabled={busy || loading}
|
||||
refreshSignal={statsSignal}
|
||||
onCopy={(code) => void copyRow(code)}
|
||||
onViewCustomer={(id) => setCustomerSelection({ id, seq: Date.now() })}
|
||||
onRevoke={(code) => setConfirmation({ kind: "revoke", code })}
|
||||
/>
|
||||
</Box>
|
||||
<RecoveryPanel selection={recoverySelection} />
|
||||
<StatsPanel refreshSignal={statsSignal} />
|
||||
<FolderPanel
|
||||
@@ -400,7 +422,6 @@ function Admin() {
|
||||
stats={listing?.stats}
|
||||
filter={listing?.folder ?? ""}
|
||||
disabled={busy || loading}
|
||||
muted={!!activeFilter}
|
||||
onSelect={(folder) => {
|
||||
// Clicking a folder chip while the expression filter is active
|
||||
// exits filter mode and returns to normal folder filtering.
|
||||
@@ -425,8 +446,7 @@ function Admin() {
|
||||
mutation.current = value;
|
||||
setBusy(value);
|
||||
}}
|
||||
onChanged={async (deleted) => {
|
||||
if (deleted === filterRef.current) filterRef.current = "";
|
||||
onChanged={async () => {
|
||||
if (activeFilter) reloadCurrent();
|
||||
else await refresh(0);
|
||||
}}
|
||||
@@ -519,7 +539,10 @@ function Admin() {
|
||||
type="number"
|
||||
required
|
||||
value={count}
|
||||
onChange={(event) => setCount(event.target.value)}
|
||||
onChange={(event) => {
|
||||
setCount(event.target.value);
|
||||
if (countError) setCountError(false);
|
||||
}}
|
||||
disabled={busy}
|
||||
error={countError}
|
||||
helperText={
|
||||
@@ -531,7 +554,10 @@ function Admin() {
|
||||
label="批次名称(可选)"
|
||||
placeholder="例如:十月赠礼"
|
||||
value={batch}
|
||||
onChange={(event) => setBatch(event.target.value)}
|
||||
onChange={(event) => {
|
||||
setBatch(event.target.value);
|
||||
if (batchError) setBatchError(false);
|
||||
}}
|
||||
disabled={busy}
|
||||
error={batchError}
|
||||
helperText={
|
||||
@@ -556,6 +582,8 @@ function Admin() {
|
||||
<Alert
|
||||
severity={notice.error ? "error" : "success"}
|
||||
role="status"
|
||||
closeText="关闭"
|
||||
onClose={notice.error ? undefined : () => setNotice(null)}
|
||||
sx={{ mb: 3 }}
|
||||
>
|
||||
{notice.text}
|
||||
@@ -637,7 +665,7 @@ function Admin() {
|
||||
</Stack>
|
||||
{loading && <LinearProgress aria-label="正在加载兑换码" />}
|
||||
{listError && (
|
||||
<Alert severity="error" sx={{ m: 2 }}>
|
||||
<Alert severity="error" role="alert" sx={{ m: 2 }}>
|
||||
{listError}
|
||||
{(listing || allCodes) && " 以下保留上次加载的数据。"}
|
||||
<Button onClick={() => reloadCurrent()}>重新加载</Button>
|
||||
@@ -693,18 +721,17 @@ function Admin() {
|
||||
busy || loading || !!listError || !visibleCodes.length
|
||||
}
|
||||
checked={
|
||||
!!visibleCodes.length &&
|
||||
selectedIDs.length === visibleCodes.length
|
||||
!!pageIDs.length && pageSelected.length === pageIDs.length
|
||||
}
|
||||
indeterminate={
|
||||
selectedIDs.length > 0 &&
|
||||
selectedIDs.length < visibleCodes.length
|
||||
pageSelected.length > 0 &&
|
||||
pageSelected.length < pageIDs.length
|
||||
}
|
||||
onChange={(event) =>
|
||||
setSelectedIDs(
|
||||
setSelectedIDs((ids) =>
|
||||
event.target.checked
|
||||
? visibleCodes.map((code) => code.id)
|
||||
: [],
|
||||
? [...new Set([...ids, ...pageIDs])]
|
||||
: ids.filter((id) => !pageIDs.includes(id)),
|
||||
)
|
||||
}
|
||||
/>
|
||||
@@ -806,14 +833,10 @@ function Admin() {
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Typography variant="body2" sx={{ whiteSpace: "nowrap" }}>
|
||||
{new Date(code.created * 1000).toLocaleDateString(
|
||||
"zh-CN",
|
||||
)}
|
||||
{formatTime(code.created).slice(0, 10)}
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary">
|
||||
{new Date(code.created * 1000).toLocaleTimeString(
|
||||
"zh-CN",
|
||||
)}
|
||||
{formatTime(code.created).slice(11)}
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell onClick={(e) => e.stopPropagation()}>
|
||||
@@ -825,8 +848,9 @@ function Admin() {
|
||||
onClick={() =>
|
||||
setCustomerSelection({ id: code.id, seq: Date.now() })
|
||||
}
|
||||
sx={{ whiteSpace: "nowrap", flexShrink: 0 }}
|
||||
>
|
||||
查看卡密 / 补单
|
||||
查看兑换码 / 补单
|
||||
</Button>
|
||||
<Tooltip
|
||||
describeChild
|
||||
@@ -955,9 +979,16 @@ function Admin() {
|
||||
) : (
|
||||
<>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{listing?.folder
|
||||
? `第 ${listing.page + 1} 页`
|
||||
: `共 ${listing?.stats.total ?? 0} 条 · 第 ${(listing?.page ?? 0) + 1} / ${Math.max(1, Math.ceil((listing?.stats.total ?? 0) / 100))} 页`}
|
||||
{(() => {
|
||||
const total = listing?.folder
|
||||
? listing.folder === "unfiled"
|
||||
? (listing?.stats.unfiled ?? 0)
|
||||
: (listing?.folders.find(
|
||||
(folder) => folder.id === listing.folder,
|
||||
)?.count ?? 0)
|
||||
: (listing?.stats.total ?? 0);
|
||||
return `共 ${total} 条 · 第 ${(listing?.page ?? 0) + 1} / ${Math.max(1, Math.ceil(total / 100))} 页`;
|
||||
})()}
|
||||
</Typography>
|
||||
<Stack direction="row" spacing={1}>
|
||||
<Button
|
||||
@@ -988,6 +1019,7 @@ function Admin() {
|
||||
fullWidth
|
||||
maxWidth="xs"
|
||||
aria-labelledby="move-dialog-title"
|
||||
aria-describedby="move-dialog-description"
|
||||
>
|
||||
<DialogTitle id="move-dialog-title">
|
||||
移动 {selectedIDs.length} 枚兑换码
|
||||
@@ -999,6 +1031,10 @@ function Admin() {
|
||||
value={moveTarget}
|
||||
disabled={busy}
|
||||
onChange={(event) => setMoveTarget(event.target.value)}
|
||||
slotProps={{
|
||||
select: { displayEmpty: true },
|
||||
inputLabel: { shrink: true },
|
||||
}}
|
||||
sx={{ mt: 1 }}
|
||||
>
|
||||
<MenuItem value="">未分类</MenuItem>
|
||||
@@ -1012,7 +1048,7 @@ function Admin() {
|
||||
</MenuItem>
|
||||
))}
|
||||
</TextField>
|
||||
<DialogContentText sx={{ mt: 2 }}>
|
||||
<DialogContentText id="move-dialog-description" sx={{ mt: 2 }}>
|
||||
只修改归属分类,不改变兑换码、账号和订单状态。
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
@@ -1035,13 +1071,15 @@ function Admin() {
|
||||
onClose={() => {
|
||||
if (!busy) setConfirmation(null);
|
||||
}}
|
||||
role="alertdialog"
|
||||
aria-labelledby="admin-dialog-title"
|
||||
aria-describedby="admin-dialog-description"
|
||||
maxWidth="xs"
|
||||
fullWidth
|
||||
>
|
||||
<DialogTitle id="admin-dialog-title">停用这枚兑换码?</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
<DialogContentText id="admin-dialog-description">
|
||||
{`尾号 ${confirmation?.code.hint ?? ""} 的兑换码将无法使用。此操作不可撤销。`}
|
||||
</DialogContentText>
|
||||
</DialogContent>
|
||||
@@ -1064,10 +1102,12 @@ function Admin() {
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
<Snackbar
|
||||
key={copySeq}
|
||||
open={!!copyNotice}
|
||||
autoHideDuration={4000}
|
||||
onClose={() => setCopyNotice("")}
|
||||
message={copyNotice}
|
||||
slotProps={{ content: { role: "status" } }}
|
||||
/>
|
||||
</Shell>
|
||||
);
|
||||
|
||||
@@ -24,3 +24,23 @@ export type AdminStatsDetail = {
|
||||
export function stats() {
|
||||
return adminApi<AdminStatsDetail>("/api/admin/stats");
|
||||
}
|
||||
export type AdminCode = {
|
||||
copyable: boolean;
|
||||
folder: string;
|
||||
id: string;
|
||||
hint: string;
|
||||
batch: string;
|
||||
months: number;
|
||||
status: string;
|
||||
username: string;
|
||||
message: string;
|
||||
created: number;
|
||||
updated?: number;
|
||||
progress?: number;
|
||||
};
|
||||
// 全站统一的时间呈现:YYYY-MM-DD HH:mm:ss(与统计表日期风格一致)。
|
||||
export function formatTime(seconds: number): string {
|
||||
const d = new Date(seconds * 1000);
|
||||
const p = (n: number) => String(n).padStart(2, "0");
|
||||
return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())} ${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
|
||||
}
|
||||
+92
-96
@@ -6,7 +6,6 @@ import {
|
||||
Alert,
|
||||
Box,
|
||||
Button,
|
||||
CircularProgress,
|
||||
Dialog,
|
||||
DialogActions,
|
||||
DialogContent,
|
||||
@@ -26,11 +25,11 @@ import {
|
||||
import ArrowForwardRounded from "@mui/icons-material/ArrowForwardRounded";
|
||||
import ArrowOutwardRounded from "@mui/icons-material/ArrowOutwardRounded";
|
||||
import ExpandMoreRounded from "@mui/icons-material/ExpandMoreRounded";
|
||||
import FactCheckRounded from "@mui/icons-material/FactCheckRounded";
|
||||
import ShieldOutlined from "@mui/icons-material/ShieldOutlined";
|
||||
import HistoryRounded from "@mui/icons-material/HistoryRounded";
|
||||
import { mount, request, Shell } from "./shared";
|
||||
import { AppearanceMenu } from "./AppearanceMenu";
|
||||
import { EligibilityCard } from "./EligibilityCard";
|
||||
|
||||
type Result = {
|
||||
status?: string;
|
||||
@@ -60,19 +59,18 @@ function App() {
|
||||
const [locked, setLocked] = useState(false);
|
||||
const [exhausted, setExhausted] = useState(false);
|
||||
const [validation, setValidation] = useState(false);
|
||||
const [checking, setChecking] = useState(false);
|
||||
const [checkResult, setCheckResult] = useState<{
|
||||
severity: "success" | "warning" | "info";
|
||||
message: string;
|
||||
} | null>(null);
|
||||
// 本次会话的进度来自「兑换」还是「查询」,驱动进度区标题与区域命名。
|
||||
const fromRedeem = useRef(false);
|
||||
const timer = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
|
||||
const controller = useRef<AbortController | null>(null);
|
||||
const inFlight = useRef(false);
|
||||
const progressPanel = useRef<HTMLDivElement>(null);
|
||||
const progressHeading = useRef<HTMLParagraphElement>(null);
|
||||
const resultAlert = useRef<HTMLDivElement>(null);
|
||||
const form = useRef<HTMLFormElement>(null);
|
||||
const current = useRef<Input>({ code: "", username: "" });
|
||||
const attempt = useRef(0);
|
||||
const cleanCode = code.trim().toUpperCase();
|
||||
const cleanCode = code.replace(/\s+/g, "").toUpperCase();
|
||||
const cleanUser = username.trim().replace(/^@/, "").toLowerCase();
|
||||
const codeValid = /^XG-[A-F0-9]{48}$/.test(cleanCode);
|
||||
const userValid = /^[a-z0-9_]{1,15}$/.test(cleanUser);
|
||||
@@ -126,6 +124,10 @@ function App() {
|
||||
}
|
||||
function apply(ok: boolean, data: Result) {
|
||||
if (data.status === "paused") setService("paused");
|
||||
// If focus sits in the progress panel and this update unmounts it
|
||||
// (terminal states), hand focus to the result alert instead of <body>.
|
||||
const refocus =
|
||||
progressPanel.current?.contains(document.activeElement) ?? false;
|
||||
setResult({
|
||||
...data,
|
||||
message:
|
||||
@@ -141,9 +143,11 @@ function App() {
|
||||
? "error"
|
||||
: data.status === "succeeded"
|
||||
? "success"
|
||||
: data.status === "review" || data.status === "revoked"
|
||||
? "warning"
|
||||
: "info",
|
||||
: data.status === "revoked"
|
||||
? "error"
|
||||
: data.status === "review"
|
||||
? "warning"
|
||||
: "info",
|
||||
);
|
||||
if (data.payment_declined) {
|
||||
setProgress(null);
|
||||
@@ -162,6 +166,11 @@ function App() {
|
||||
setProgress(null);
|
||||
if (ok && data.status === "active") setLocked(false);
|
||||
}
|
||||
if (refocus)
|
||||
requestAnimationFrame(() => {
|
||||
if (!progressPanel.current?.contains(document.activeElement))
|
||||
resultAlert.current?.focus();
|
||||
});
|
||||
}
|
||||
async function send(path: string) {
|
||||
controller.current = new AbortController();
|
||||
@@ -214,7 +223,7 @@ function App() {
|
||||
}
|
||||
return form.current!.reportValidity();
|
||||
}
|
||||
function start() {
|
||||
function start(keepProgress = false) {
|
||||
if (inFlight.current) return false;
|
||||
clearTimeout(timer.current);
|
||||
current.current = { code: cleanCode, username: cleanUser };
|
||||
@@ -223,13 +232,18 @@ function App() {
|
||||
setBusy(true);
|
||||
setExhausted(false);
|
||||
setSeverity("info");
|
||||
setProgress(5);
|
||||
// 继续查询保留已显示的进度,避免进度条倒退(apply 维持单调不降)。
|
||||
if (!keepProgress) setProgress(5);
|
||||
scroll();
|
||||
// The submit/query buttons disable themselves; park focus on the progress
|
||||
// heading so keyboard and screen-reader users are not dropped to <body>.
|
||||
requestAnimationFrame(() => progressHeading.current?.focus());
|
||||
return true;
|
||||
}
|
||||
async function redeem() {
|
||||
setConfirmation(false);
|
||||
if (service !== "enabled" || result?.payment_declined) return;
|
||||
fromRedeem.current = true;
|
||||
if (!start()) return;
|
||||
setResult({ status: "processing", message: "正在核实 X 账号和赠送资格…" });
|
||||
try {
|
||||
@@ -252,53 +266,37 @@ function App() {
|
||||
}
|
||||
function edit(field: "code" | "username", value: string) {
|
||||
if (field === "code") setCode(value);
|
||||
else {
|
||||
setUsername(value);
|
||||
setCheckResult(null);
|
||||
}
|
||||
else setUsername(value);
|
||||
// 与已提交的键值对比较(同一套清洗规则):只在真正变化时解锁并清空
|
||||
// 结果;空白位置等外观编辑保留当前展示(锁定也继续生效)。
|
||||
const differs =
|
||||
field === "code"
|
||||
? value.replace(/\s+/g, "").toUpperCase() !== current.current.code
|
||||
: value.trim().replace(/^@/, "").toLowerCase() !==
|
||||
current.current.username;
|
||||
if (!differs) return;
|
||||
if (locked) setLocked(false);
|
||||
setResult(null);
|
||||
setProgress(null);
|
||||
setExhausted(false);
|
||||
// A lost response stays query-only until the server returns a known state.
|
||||
}
|
||||
// Advisory only: the result never blocks or alters the redemption flow.
|
||||
async function runCheck() {
|
||||
if (checking || busy || !userValid) return;
|
||||
setChecking(true);
|
||||
setCheckResult(null);
|
||||
try {
|
||||
const { ok, data } = await request<{
|
||||
eligible?: boolean;
|
||||
message?: string;
|
||||
}>("/api/check", { username: cleanUser }, AbortSignal.timeout(45000));
|
||||
if (ok && typeof data.eligible === "boolean") {
|
||||
setCheckResult(
|
||||
data.eligible
|
||||
? { severity: "success", message: "该账号当前可以接收赠送。" }
|
||||
: {
|
||||
severity: "warning",
|
||||
message: `该账号当前无法接收赠送:${data.message || "原因未知。"}`,
|
||||
},
|
||||
);
|
||||
} else {
|
||||
setCheckResult({
|
||||
severity: "info",
|
||||
message: data.message || "暂时无法检测,请稍后再试。",
|
||||
});
|
||||
}
|
||||
} catch {
|
||||
setCheckResult({ severity: "info", message: "暂时无法检测,请稍后再试。" });
|
||||
} finally {
|
||||
setChecking(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Shell>
|
||||
<Paper
|
||||
variant="outlined"
|
||||
sx={{ p: { xs: 2.5, sm: 4 }, borderRadius: "28px" }}
|
||||
<Shell maxWidth="md">
|
||||
<Box
|
||||
sx={{
|
||||
display: "grid",
|
||||
gridTemplateColumns: {
|
||||
xs: "1fr",
|
||||
md: "minmax(0, 7fr) minmax(0, 5fr)",
|
||||
},
|
||||
gap: 3,
|
||||
}}
|
||||
>
|
||||
<Paper
|
||||
variant="outlined"
|
||||
sx={{ p: { xs: 2.5, sm: 4 }, borderRadius: "28px" }}
|
||||
>
|
||||
<Stack
|
||||
direction="row"
|
||||
alignItems="center"
|
||||
@@ -329,7 +327,7 @@ function App() {
|
||||
ref={form}
|
||||
onSubmit={(event) => {
|
||||
event.preventDefault();
|
||||
if (service === "enabled" && !result?.payment_declined && valid() && !locked && !busy)
|
||||
if (service === "enabled" && !result?.payment_declined && result?.status !== "revoked" && valid() && !locked && !busy)
|
||||
setConfirmation(true);
|
||||
}}
|
||||
noValidate
|
||||
@@ -348,12 +346,13 @@ function App() {
|
||||
error={validation && !codeValid}
|
||||
helperText={
|
||||
validation && !codeValid
|
||||
? "请输入 XG- 开头、后接 48 位字母或数字的完整兑换码。"
|
||||
? "请输入 XG- 开头、后接 48 位十六进制字符(0-9、A-F)的完整兑换码。"
|
||||
: "请保留兑换码,后续查询仍需使用。"
|
||||
}
|
||||
slotProps={{
|
||||
htmlInput: { maxLength: 80, spellCheck: false },
|
||||
input: { sx: { fontFamily: "monospace", fontSize: 14 } },
|
||||
input: { sx: { fontFamily: "monospace", fontSize: 16 } },
|
||||
inputLabel: { shrink: true },
|
||||
}}
|
||||
/>
|
||||
<TextField
|
||||
@@ -383,44 +382,23 @@ function App() {
|
||||
},
|
||||
}}
|
||||
/>
|
||||
<Box>
|
||||
<Button
|
||||
variant="text"
|
||||
size="small"
|
||||
disabled={!userValid || busy || checking}
|
||||
onClick={() => void runCheck()}
|
||||
startIcon={
|
||||
checking ? (
|
||||
<CircularProgress size={16} aria-hidden="true" />
|
||||
) : (
|
||||
<FactCheckRounded />
|
||||
)
|
||||
}
|
||||
>
|
||||
{checking ? "正在检测…" : "检测可否接收赠送"}
|
||||
</Button>
|
||||
{checkResult && (
|
||||
<Alert
|
||||
severity={checkResult.severity}
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
sx={{ mt: 1 }}
|
||||
>
|
||||
{checkResult.message}
|
||||
</Alert>
|
||||
)}
|
||||
</Box>
|
||||
<Button
|
||||
type="submit"
|
||||
variant="contained"
|
||||
size="large"
|
||||
disabled={busy || locked || service !== "enabled" || result?.payment_declined}
|
||||
disabled={busy || locked || service !== "enabled" || result?.payment_declined || result?.status === "revoked"}
|
||||
endIcon={<ArrowForwardRounded />}
|
||||
>
|
||||
{service === "paused"
|
||||
{service === "loading"
|
||||
? "正在检查服务状态…"
|
||||
: service === "unknown"
|
||||
? "服务状态未知,请稍后再试"
|
||||
: service === "paused"
|
||||
? "充值已暂停"
|
||||
: result?.payment_declined
|
||||
? "付款被拒,请联系管理员"
|
||||
: result?.status === "revoked"
|
||||
? "兑换码已停用"
|
||||
: busy
|
||||
? "正在处理,请稍候"
|
||||
: locked
|
||||
@@ -435,6 +413,7 @@ function App() {
|
||||
disabled={busy}
|
||||
startIcon={<HistoryRounded />}
|
||||
onClick={() => {
|
||||
fromRedeem.current = false;
|
||||
if (valid() && start()) {
|
||||
setResult({ message: "正在查询原订单,不会再次扣款…" });
|
||||
void query();
|
||||
@@ -449,7 +428,7 @@ function App() {
|
||||
{progress !== null && (
|
||||
<Box
|
||||
component="section"
|
||||
aria-label="兑换进度"
|
||||
aria-labelledby="progress-heading"
|
||||
sx={{
|
||||
mt: 3,
|
||||
p: 2,
|
||||
@@ -463,10 +442,16 @@ function App() {
|
||||
spacing={1}
|
||||
sx={{ mb: 1.5 }}
|
||||
>
|
||||
<Typography variant="body2" fontWeight={600}>
|
||||
<Typography
|
||||
ref={progressHeading}
|
||||
id="progress-heading"
|
||||
tabIndex={-1}
|
||||
variant="body2"
|
||||
fontWeight={600}
|
||||
>
|
||||
{result?.status === "succeeded"
|
||||
? "兑换完成"
|
||||
: busy
|
||||
: fromRedeem.current
|
||||
? "兑换进度"
|
||||
: "原订单进度"}
|
||||
</Typography>
|
||||
@@ -477,7 +462,7 @@ function App() {
|
||||
<LinearProgress
|
||||
variant="determinate"
|
||||
value={progress}
|
||||
aria-label="兑换阶段进度"
|
||||
aria-label="流程阶段进度"
|
||||
color={result?.status === "succeeded" ? "success" : "primary"}
|
||||
sx={{ height: 6, borderRadius: 3 }}
|
||||
/>
|
||||
@@ -510,12 +495,18 @@ function App() {
|
||||
component="p"
|
||||
sx={{ mt: 2 }}
|
||||
>
|
||||
百分比表示流程阶段,不是预计耗时。请勿重复提交。
|
||||
{result?.status === "succeeded"
|
||||
? "百分比表示流程阶段,不是预计耗时。请保留兑换码备查。"
|
||||
: result?.status === "review"
|
||||
? "百分比表示流程阶段,不是预计耗时。"
|
||||
: "百分比表示流程阶段,不是预计耗时。请勿重复提交。"}
|
||||
</Typography>
|
||||
</Box>
|
||||
)}
|
||||
{result && (
|
||||
<Alert
|
||||
ref={resultAlert}
|
||||
tabIndex={-1}
|
||||
severity={severity}
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
@@ -532,7 +523,8 @@ function App() {
|
||||
sx={{ mt: 2 }}
|
||||
onClick={() => {
|
||||
// Resume status polling only; never re-submits the redemption.
|
||||
if (valid() && start()) {
|
||||
fromRedeem.current = false;
|
||||
if (valid() && start(true)) {
|
||||
setResult({
|
||||
status: result.status,
|
||||
message: "正在继续查询原订单,不会再次扣款…",
|
||||
@@ -546,9 +538,10 @@ function App() {
|
||||
)}
|
||||
{result?.status === "succeeded" && (
|
||||
<Button
|
||||
href="https://x.com/"
|
||||
href="https://x.com/i/premium"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
variant="contained"
|
||||
endIcon={<ArrowOutwardRounded />}
|
||||
fullWidth
|
||||
sx={{ mt: 2 }}
|
||||
@@ -566,6 +559,8 @@ function App() {
|
||||
</Typography>
|
||||
</Stack>
|
||||
</Paper>
|
||||
<EligibilityCard />
|
||||
</Box>
|
||||
<Box component="section" aria-labelledby="faq-title" sx={{ mt: 4 }}>
|
||||
<Typography id="faq-title" variant="h3" component="h2" sx={{ mb: 1 }}>
|
||||
常见问题
|
||||
@@ -577,7 +572,7 @@ function App() {
|
||||
],
|
||||
[
|
||||
"账号暂时无法接收赠送怎么办?",
|
||||
"X 会根据账号情况决定是否允许接收 Premium 赠送。兑换前可先点击用户名旁的「检测可否接收赠送」确认当前资格。首次建单前资格未通过,兑换码不会使用;已有待核实订单时,请使用原兑换码和账号重新检查,符合条件且尚未付款时会继续兑换。",
|
||||
"X 会根据账号情况决定是否允许接收 Premium 赠送。兑换前可先用本页的「检测赠送资格」确认账号当前状态。首次建单前资格未通过,兑换码不会使用;已有待核实订单时,请使用原兑换码和账号重新检查,符合条件且尚未付款时会继续兑换。",
|
||||
],
|
||||
[
|
||||
"等待较久或关闭页面后,如何查询?",
|
||||
@@ -602,7 +597,7 @@ function App() {
|
||||
>
|
||||
<Typography fontWeight={500}>{title}</Typography>
|
||||
</AccordionSummary>
|
||||
<AccordionDetails sx={{ px: 0, pb: 3 }}>
|
||||
<AccordionDetails id={`faq-content-${index}`} sx={{ px: 0, pb: 3 }}>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
{text}
|
||||
</Typography>
|
||||
@@ -640,6 +635,7 @@ function App() {
|
||||
open={confirmation}
|
||||
onClose={() => setConfirmation(false)}
|
||||
aria-labelledby="redeem-dialog-title"
|
||||
aria-describedby="redeem-dialog-description"
|
||||
fullWidth
|
||||
maxWidth="xs"
|
||||
>
|
||||
@@ -649,7 +645,7 @@ function App() {
|
||||
: "确认接收 Premium 的账号"}
|
||||
</DialogTitle>
|
||||
<DialogContent>
|
||||
<DialogContentText>
|
||||
<DialogContentText id="redeem-dialog-description">
|
||||
接收账号为 <strong>@{cleanUser}</strong>。
|
||||
{result?.status === "review"
|
||||
? "将重新核对账号资格和原订单;符合条件且尚未付款时继续付款,已提交过付款的订单只核实结果。"
|
||||
@@ -665,7 +661,7 @@ function App() {
|
||||
disabled={service !== "enabled"}
|
||||
onClick={() => void redeem()}
|
||||
>
|
||||
确认兑换
|
||||
{result?.status === "review" ? "继续兑换" : "确认兑换"}
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
export const codeStatus: Record<
|
||||
string,
|
||||
{ label: string; color: "default" | "primary" | "success" | "warning" }
|
||||
> = {
|
||||
active: { label: "可使用", color: "primary" },
|
||||
processing: { label: "处理中", color: "primary" },
|
||||
succeeded: { label: "已完成", color: "success" },
|
||||
review: { label: "待核实", color: "warning" },
|
||||
revoked: { label: "已停用", color: "default" },
|
||||
};
|
||||
+86
-19
@@ -31,13 +31,42 @@ type Token =
|
||||
|
||||
function tokenize(src: string): Token[] {
|
||||
// 中文输入法容错:全角括号、冒号、引号、叹号、等号统一归一为半角。
|
||||
src = src
|
||||
.replace(/(/g, "(")
|
||||
.replace(/)/g, ")")
|
||||
.replace(/:/g, ":")
|
||||
.replace(/!/g, "!")
|
||||
.replace(/=/g, "=")
|
||||
.replace(/["“”]/g, '"');
|
||||
// 引号内的字面内容保持原样(批次名可能本身含全角标点)。
|
||||
let normalized = "";
|
||||
let inString = false;
|
||||
let escaped = false;
|
||||
for (const raw of src) {
|
||||
if (inString) {
|
||||
if (escaped) {
|
||||
normalized += raw;
|
||||
escaped = false;
|
||||
continue;
|
||||
}
|
||||
if (raw === "\\") {
|
||||
normalized += raw;
|
||||
escaped = true;
|
||||
continue;
|
||||
}
|
||||
// 未转义的全角引号在字符串内视为闭合(中文输入法自动配对场景);
|
||||
// 名称字面的全角引号由 quoteValue 转义为 \” 绕过。
|
||||
if (raw === '"' || /["“”]/.test(raw)) {
|
||||
normalized += '"';
|
||||
inString = false;
|
||||
continue;
|
||||
}
|
||||
normalized += raw;
|
||||
continue;
|
||||
}
|
||||
const char = /["“”]/.test(raw) ? '"' : raw;
|
||||
if (char === '"') inString = true;
|
||||
normalized += char
|
||||
.replace(/(/g, "(")
|
||||
.replace(/)/g, ")")
|
||||
.replace(/:/g, ":")
|
||||
.replace(/!/g, "!")
|
||||
.replace(/=/g, "=");
|
||||
}
|
||||
src = normalized;
|
||||
const tokens: Token[] = [];
|
||||
let index = 0;
|
||||
while (index < src.length) {
|
||||
@@ -82,10 +111,22 @@ function tokenize(src: string): Token[] {
|
||||
continue;
|
||||
}
|
||||
if (char === '"') {
|
||||
const end = src.indexOf('"', index + 1);
|
||||
if (end === -1)
|
||||
throw new Error("引号不匹配:批次名称的英文双引号没有闭合。");
|
||||
tokens.push({ kind: "string", text: src.slice(index + 1, end) });
|
||||
// 支持 \" 与 \\ 转义,与 quoteValue 的序列化互逆。
|
||||
let end = index + 1;
|
||||
let text = "";
|
||||
for (;;) {
|
||||
if (end >= src.length)
|
||||
throw new Error("引号不匹配:批次名称的英文双引号没有闭合。");
|
||||
if (src[end] === "\\" && end + 1 < src.length) {
|
||||
text += src[end + 1];
|
||||
end += 2;
|
||||
continue;
|
||||
}
|
||||
if (src[end] === '"') break;
|
||||
text += src[end];
|
||||
end++;
|
||||
}
|
||||
tokens.push({ kind: "string", text });
|
||||
index = end + 1;
|
||||
continue;
|
||||
}
|
||||
@@ -108,11 +149,13 @@ type Node =
|
||||
| { type: "or"; left: Node; right: Node }
|
||||
| { type: "and"; left: Node; right: Node }
|
||||
| { type: "not"; operand: Node }
|
||||
| { type: "condition"; field: Field; value: string; negate: boolean };
|
||||
// literal: 值来自引号串,哨兵值("-")按字面名称处理。
|
||||
| { type: "condition"; field: Field; value: string; negate: boolean; literal?: boolean };
|
||||
|
||||
// 调色板模式使用的扁平词元,按表达式中的出现顺序记录。
|
||||
// condition.literal: 值来自引号串(序列化时保持引号,哨兵 "-" 按字面名称处理)。
|
||||
export type ExpressionToken =
|
||||
| { kind: "condition"; field: Field; value: string; negate: boolean }
|
||||
| { kind: "condition"; field: Field; value: string; negate: boolean; literal?: boolean }
|
||||
| { kind: "not" }
|
||||
| { kind: "and" }
|
||||
| { kind: "or" }
|
||||
@@ -193,8 +236,16 @@ function parse(src: string): { root: Node; flat: ExpressionToken[] } {
|
||||
throw new Error(`「${field.text}」后缺少 : 或 !=。`);
|
||||
next();
|
||||
const value = peek();
|
||||
if (!value || (value.kind !== "word" && value.kind !== "string"))
|
||||
if (!value || (value.kind !== "word" && value.kind !== "string")) {
|
||||
if (
|
||||
value &&
|
||||
(value.kind === "and" || value.kind === "or" || value.kind === "not")
|
||||
)
|
||||
throw new Error(
|
||||
`「${field.text}:」后遇到逻辑运算符;如果名称本身含 and / or / not / 非,请用英文引号包裹,如 ${field.text}:"非"。`,
|
||||
);
|
||||
throw new Error(`「${field.text}:」后缺少值。`);
|
||||
}
|
||||
next();
|
||||
let normalized = value.text;
|
||||
if (name === "status") {
|
||||
@@ -214,14 +265,30 @@ function parse(src: string): { root: Node; flat: ExpressionToken[] } {
|
||||
} else if (!value.text) {
|
||||
throw new Error("「username:」后需要账号名;未绑定请使用 username:-。");
|
||||
}
|
||||
flat.push({ kind: "condition", field: name, value: normalized, negate });
|
||||
return { type: "condition", field: name, value: normalized, negate };
|
||||
flat.push({
|
||||
kind: "condition",
|
||||
field: name,
|
||||
value: normalized,
|
||||
negate,
|
||||
literal: value.kind === "string",
|
||||
});
|
||||
return {
|
||||
type: "condition",
|
||||
field: name,
|
||||
value: normalized,
|
||||
negate,
|
||||
literal: value.kind === "string",
|
||||
};
|
||||
}
|
||||
|
||||
const root = parseExpr();
|
||||
if (position < tokens.length) {
|
||||
const rest = tokens[position];
|
||||
if (rest.kind === "rparen") throw new Error("括号不匹配:多余的右括号。");
|
||||
if (rest.kind === "colon" || rest.kind === "eq" || rest.kind === "neq")
|
||||
throw new Error(
|
||||
'值中包含 : 或 = 等特殊字符;请用英文引号包裹名称,如 folder:"国庆:活动"。',
|
||||
);
|
||||
if (rest.kind === "lparen")
|
||||
throw new Error("「(」前缺少逻辑运算符(and / or)。");
|
||||
if (rest.kind === "word" || rest.kind === "string") {
|
||||
@@ -259,7 +326,7 @@ export function parseFilter(src: string): (code: CodeRow) => boolean {
|
||||
break;
|
||||
case "folder":
|
||||
matched =
|
||||
node.value === "-"
|
||||
node.value === "-" && !node.literal
|
||||
? !code.batch
|
||||
: code.batch.toLowerCase() === node.value.toLowerCase();
|
||||
break;
|
||||
@@ -268,7 +335,7 @@ export function parseFilter(src: string): (code: CodeRow) => boolean {
|
||||
break;
|
||||
case "username":
|
||||
matched =
|
||||
node.value === "-"
|
||||
node.value === "-" && !node.literal
|
||||
? !code.username
|
||||
: (code.username ?? "").toLowerCase() ===
|
||||
node.value.toLowerCase();
|
||||
@@ -287,4 +354,4 @@ export function parseExpressionTokens(src: string): ExpressionToken[] {
|
||||
}
|
||||
|
||||
export const FILTER_HINT =
|
||||
"条件:folder:批次名、status:状态、months:时长、username:账号;逻辑:and、or、not、括号;!= 取反;folder:- 未分类、username:- 未绑定。";
|
||||
"条件:folder:批次名、status:状态、months:时长、username:账号;逻辑:and、or、not、括号;!= 取反;folder:- 未分类、username:- 未绑定;名称含空格、冒号或保留字时用英文引号包裹,如 folder:\"and\"。";
|
||||
+43
-11
@@ -46,17 +46,21 @@ class ErrorBoundary extends Component<
|
||||
return { failed: true };
|
||||
}
|
||||
render() {
|
||||
if (this.state.failed)
|
||||
if (this.state.failed) {
|
||||
const admin = window.location.pathname.startsWith("/admin");
|
||||
return (
|
||||
<Container sx={{ py: 8 }}>
|
||||
<Alert severity="error">
|
||||
页面暂时无法显示。若已提交兑换,请保留兑换码,重新打开页面后查询原订单;不要重复兑换。
|
||||
{admin
|
||||
? "管理页暂时无法显示。进行中的兑换不受影响,请重新打开后继续核实。"
|
||||
: "页面暂时无法显示。若已提交兑换,请保留兑换码,重新打开页面后查询原订单;不要重复兑换。"}
|
||||
</Alert>
|
||||
<Button href="/" sx={{ mt: 2 }}>
|
||||
重新打开兑换页
|
||||
<Button href={admin ? "/admin" : "/"} sx={{ mt: 2 }}>
|
||||
{admin ? "重新打开管理页" : "重新打开兑换页"}
|
||||
</Button>
|
||||
</Container>
|
||||
);
|
||||
}
|
||||
return this.props.children;
|
||||
}
|
||||
}
|
||||
@@ -84,18 +88,45 @@ export function mount(node: ReactNode) {
|
||||
|
||||
export function Shell({
|
||||
admin = false,
|
||||
maxWidth,
|
||||
children,
|
||||
}: {
|
||||
admin?: boolean;
|
||||
maxWidth?: "xs" | "sm" | "md" | "lg";
|
||||
children: ReactNode;
|
||||
}) {
|
||||
return (
|
||||
<Container
|
||||
id="main"
|
||||
component="main"
|
||||
maxWidth={admin ? "lg" : "sm"}
|
||||
sx={{ py: { xs: 3, sm: 6 } }}
|
||||
>
|
||||
<>
|
||||
<Link
|
||||
href="#main"
|
||||
sx={{
|
||||
position: "absolute",
|
||||
left: 16,
|
||||
top: -64,
|
||||
zIndex: (theme) => theme.zIndex.tooltip,
|
||||
px: 2,
|
||||
py: 1,
|
||||
borderRadius: 1,
|
||||
bgcolor: "background.paper",
|
||||
color: "text.primary",
|
||||
fontWeight: 600,
|
||||
transition: "top 160ms ease",
|
||||
"&:focus-visible": { top: 16 },
|
||||
"@media (prefers-reduced-motion: reduce)": { transition: "none" },
|
||||
}}
|
||||
>
|
||||
跳转到主要内容
|
||||
</Link>
|
||||
<Container
|
||||
id="main"
|
||||
component="main"
|
||||
tabIndex={-1}
|
||||
maxWidth={maxWidth ?? (admin ? "lg" : "sm")}
|
||||
sx={{
|
||||
py: { xs: 3, sm: 6 },
|
||||
"&:focus-visible": { outline: "none" },
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
<Box
|
||||
component="footer"
|
||||
@@ -144,6 +175,7 @@ export function Shell({
|
||||
GitHub
|
||||
</Link>
|
||||
</Box>
|
||||
</Container>
|
||||
</Container>
|
||||
</>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,648 @@
|
||||
package checkout
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
"xgift/internal/vault"
|
||||
)
|
||||
|
||||
// Cards are stored as an encrypted JSON array under "cards". A single legacy
|
||||
// "card" record keeps working for vaults that never added another card.
|
||||
const (
|
||||
cardsRecord = "cards"
|
||||
legacyCardKey = "card"
|
||||
cardBlockRecord = "payment-card-blocks"
|
||||
)
|
||||
|
||||
// paymentCardCooldown is how long a declined card stays out of rotation while
|
||||
// other cards are available. A provider no-retry instruction blocks it until an
|
||||
// operator explicitly unblocks it.
|
||||
const paymentCardCooldown = 30 * time.Minute
|
||||
|
||||
var ErrNoUsableCard = errors.New("no usable payment card is available; every configured card may be blocked or cooling down")
|
||||
|
||||
var (
|
||||
cardNumberPattern = regexp.MustCompile(`^[0-9]{12,19}$`)
|
||||
cardMonthPattern = regexp.MustCompile(`^(0[1-9]|1[0-2])$`)
|
||||
cardYearPattern = regexp.MustCompile(`^[0-9]{4}$`)
|
||||
cardCVCPattern = regexp.MustCompile(`^[0-9]{3,4}$`)
|
||||
cardCountry = regexp.MustCompile(`^[A-Z]{2}$`)
|
||||
)
|
||||
|
||||
// validateCard is the structural and expiry check every payment card must pass.
|
||||
func validateCard(c card) error {
|
||||
if !cardNumberPattern.MatchString(c.Number) || !cardMonthPattern.MatchString(c.Month) || !cardYearPattern.MatchString(c.Year) || !cardCVCPattern.MatchString(c.CVC) || strings.TrimSpace(c.Name) == "" || !strings.Contains(c.Email, "@") {
|
||||
return errors.New("card, cardholder name or email is incomplete")
|
||||
}
|
||||
sum := 0
|
||||
for i, n := range c.Number {
|
||||
d := int(n - '0')
|
||||
if (len(c.Number)-i)%2 == 0 {
|
||||
d *= 2
|
||||
if d > 9 {
|
||||
d -= 9
|
||||
}
|
||||
}
|
||||
sum += d
|
||||
}
|
||||
if sum%10 != 0 {
|
||||
return errors.New("card number checksum is invalid")
|
||||
}
|
||||
year, _ := strconv.Atoi(c.Year)
|
||||
month, _ := strconv.Atoi(c.Month)
|
||||
if !time.Now().Before(time.Date(year, time.Month(month)+1, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
return errors.New("card has expired")
|
||||
}
|
||||
if c.Country == "" {
|
||||
return errors.New("Stripe requires a billing address; supply the card billing country and applicable address fields")
|
||||
}
|
||||
if !cardCountry.MatchString(c.Country) {
|
||||
return errors.New("invalid supplied billing country")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// cardFingerprint identifies one card without ever exposing its number.
|
||||
func cardFingerprint(c card) string {
|
||||
sum := sha256.Sum256([]byte(c.Number + ":" + c.Month + ":" + c.Year))
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
// cardSetFingerprint covers the whole configured set so a changed set resets
|
||||
// circuit state and invalidates admin recovery previews, while rotation across
|
||||
// the same set stays stable.
|
||||
func cardSetFingerprint(cards []card) string {
|
||||
parts := make([]string, 0, len(cards))
|
||||
for _, c := range cards {
|
||||
parts = append(parts, cardFingerprint(c))
|
||||
}
|
||||
sort.Strings(parts)
|
||||
sum := sha256.Sum256([]byte(strings.Join(parts, "\n")))
|
||||
return hex.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
func cardTail(c card) string {
|
||||
if len(c.Number) < 4 {
|
||||
return "****"
|
||||
}
|
||||
return c.Number[len(c.Number)-4:]
|
||||
}
|
||||
|
||||
// readCards prefers the multi-card record and falls back to the legacy single
|
||||
// card so existing vaults keep paying without a migration step.
|
||||
func readCards(v *vault.Vault) ([]card, error) {
|
||||
raw, err := v.Get(cardsRecord)
|
||||
if err == nil {
|
||||
defer clear(raw)
|
||||
var cards []card
|
||||
if json.Unmarshal(raw, &cards) != nil || len(cards) == 0 {
|
||||
return nil, errors.New("invalid card set record")
|
||||
}
|
||||
return cards, nil
|
||||
}
|
||||
if !errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, err
|
||||
}
|
||||
raw, err = v.Get(legacyCardKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer clear(raw)
|
||||
var c card
|
||||
if json.Unmarshal(raw, &c) != nil {
|
||||
return nil, errors.New("invalid card record")
|
||||
}
|
||||
return []card{c}, nil
|
||||
}
|
||||
|
||||
// readCard keeps the legacy single-card helper working: it returns the first
|
||||
// card of the configured set, fully validated.
|
||||
func readCard(v *vault.Vault) (card, error) {
|
||||
cards, err := readCards(v)
|
||||
if err != nil {
|
||||
return card{}, err
|
||||
}
|
||||
c := cards[0]
|
||||
if err = validateCard(c); err != nil {
|
||||
return c, err
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// legacyCardFingerprint was used while the historic single card was assumed to
|
||||
// be the one that declined old orders; multi-card rotation now tracks real
|
||||
// decline evidence instead.
|
||||
|
||||
// readCardsOptional behaves like readCards but reports an unconfigured card
|
||||
// set as empty, which lets `cards add` create the first record.
|
||||
func readCardsOptional(v *vault.Vault) ([]card, error) {
|
||||
cards, err := readCards(v)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
return cards, err
|
||||
}
|
||||
|
||||
func usableCards(cards []card) []card {
|
||||
usable := make([]card, 0, len(cards))
|
||||
for _, c := range cards {
|
||||
if validateCard(c) == nil {
|
||||
usable = append(usable, c)
|
||||
}
|
||||
}
|
||||
return usable
|
||||
}
|
||||
|
||||
func cardByFingerprint(cards []card, fingerprint string) (card, bool) {
|
||||
for _, c := range cards {
|
||||
if cardFingerprint(c) == fingerprint {
|
||||
return c, true
|
||||
}
|
||||
}
|
||||
return card{}, false
|
||||
}
|
||||
|
||||
type cardBlock struct {
|
||||
Reason string `json:"reason"`
|
||||
BlockedAt int64 `json:"blocked_at"`
|
||||
Until int64 `json:"until,omitempty"`
|
||||
}
|
||||
|
||||
func readCardBlocks(v *vault.Vault) (map[string]cardBlock, error) {
|
||||
blocks := map[string]cardBlock{}
|
||||
raw, err := v.Get(cardBlockRecord)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return blocks, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer clear(raw)
|
||||
if json.Unmarshal(raw, &blocks) != nil {
|
||||
return nil, errors.New("invalid card block record")
|
||||
}
|
||||
return blocks, nil
|
||||
}
|
||||
|
||||
func saveCardBlocks(v *vault.Vault, blocks map[string]cardBlock) error {
|
||||
b, err := json.Marshal(blocks)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer clear(b)
|
||||
return v.Put(cardBlockRecord, b)
|
||||
}
|
||||
|
||||
const cardUsageRecord = "payment-card-last-used"
|
||||
|
||||
func readCardUsage(v *vault.Vault) (map[string]int64, error) {
|
||||
usage := map[string]int64{}
|
||||
raw, err := v.Get(cardUsageRecord)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return usage, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer clear(raw)
|
||||
if json.Unmarshal(raw, &usage) != nil {
|
||||
return nil, errors.New("invalid card usage record")
|
||||
}
|
||||
return usage, nil
|
||||
}
|
||||
|
||||
// touchCardUsageLocked records when a card was handed to a payment attempt.
|
||||
// Caller must hold paymentRouteMu.
|
||||
func touchCardUsageLocked(v *vault.Vault, fingerprint string) error {
|
||||
if fingerprint == "" {
|
||||
return nil
|
||||
}
|
||||
usage, err := readCardUsage(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
usage[fingerprint] = time.Now().UnixNano()
|
||||
b, err := json.Marshal(usage)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer clear(b)
|
||||
return v.Put(cardUsageRecord, b)
|
||||
}
|
||||
|
||||
// paymentCardBlocked reports whether a card is currently out of rotation,
|
||||
// either permanently blocked or inside its post-decline cooldown.
|
||||
func paymentCardBlocked(v *vault.Vault, fingerprint string) (bool, error) {
|
||||
blocks, err := readCardBlocks(v)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
block, blocked := blocks[fingerprint]
|
||||
if !blocked {
|
||||
return false, nil
|
||||
}
|
||||
return block.Until == 0 || block.Until > time.Now().Unix(), nil
|
||||
}
|
||||
|
||||
// blockPaymentCard excludes one card from rotation until an operator unblocks
|
||||
// it or changes the card set. Caller must not hold paymentRouteMu.
|
||||
func blockPaymentCard(v *vault.Vault, fingerprint, reason string) error {
|
||||
if fingerprint == "" {
|
||||
return nil
|
||||
}
|
||||
paymentRouteMu.Lock()
|
||||
defer paymentRouteMu.Unlock()
|
||||
blocks, err := readCardBlocks(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
blocks[fingerprint] = cardBlock{Reason: reason, BlockedAt: time.Now().Unix()}
|
||||
return saveCardBlocks(v, blocks)
|
||||
}
|
||||
|
||||
// coolPaymentCard keeps a declined card out of rotation for the cooldown while
|
||||
// leaving any permanent provider block in place. Caller must not hold
|
||||
// paymentRouteMu.
|
||||
func coolPaymentCard(v *vault.Vault, fingerprint, reason string) error {
|
||||
if fingerprint == "" {
|
||||
return nil
|
||||
}
|
||||
paymentRouteMu.Lock()
|
||||
defer paymentRouteMu.Unlock()
|
||||
return coolPaymentCardLocked(v, fingerprint, reason)
|
||||
}
|
||||
|
||||
func coolPaymentCardLocked(v *vault.Vault, fingerprint, reason string) error {
|
||||
if fingerprint == "" {
|
||||
return nil
|
||||
}
|
||||
blocks, err := readCardBlocks(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if existing, ok := blocks[fingerprint]; ok && existing.Until == 0 {
|
||||
return nil
|
||||
}
|
||||
blocks[fingerprint] = cardBlock{Reason: reason, BlockedAt: time.Now().Unix(), Until: time.Now().Add(paymentCardCooldown).Unix()}
|
||||
return saveCardBlocks(v, blocks)
|
||||
}
|
||||
|
||||
// UnblockPaymentCards clears every durable card block. It is an explicit
|
||||
// operator action; the recovery batch confirmation never calls it. When the
|
||||
// provider no-retry instruction paused the site and a usable card remains, the
|
||||
// pause is lifted together with the block.
|
||||
func UnblockPaymentCards(v *vault.Vault) (int, error) {
|
||||
paymentRouteMu.Lock()
|
||||
defer paymentRouteMu.Unlock()
|
||||
blocks, err := readCardBlocks(v)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if len(blocks) > 0 {
|
||||
if err = v.Put(cardBlockRecord, []byte("{}")); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
state, err := readPaymentControl(v)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if state.Paused && state.Reason == "do_not_try_again" {
|
||||
usable, e := hasUsableCard(v)
|
||||
if e != nil {
|
||||
return 0, e
|
||||
}
|
||||
if usable {
|
||||
state.Paused = false
|
||||
state.Reason = ""
|
||||
state.ConsecutiveDeclines = 0
|
||||
if err = savePaymentControl(v, state); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
return len(blocks), nil
|
||||
}
|
||||
|
||||
// hasUsableCard reports whether any configured card is not permanently
|
||||
// blocked. Cooling cards count as usable because they return automatically.
|
||||
func hasUsableCard(v *vault.Vault) (bool, error) {
|
||||
cards, err := readCards(v)
|
||||
if err != nil {
|
||||
return false, nil
|
||||
}
|
||||
blocks, err := readCardBlocks(v)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
for _, c := range cards {
|
||||
if validateCard(c) != nil {
|
||||
continue
|
||||
}
|
||||
if block, blocked := blocks[cardFingerprint(c)]; !blocked || (block.Until != 0 && block.Until <= time.Now().Unix()) {
|
||||
return true, nil
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// CardStatus is a number-free view of one configured card for the CLI.
|
||||
type CardStatus struct {
|
||||
Last4 string `json:"last4"`
|
||||
Usable bool `json:"usable"`
|
||||
Problem string `json:"problem,omitempty"`
|
||||
Blocked string `json:"blocked,omitempty"`
|
||||
CoolingSeconds int64 `json:"cooling_seconds,omitempty"`
|
||||
}
|
||||
|
||||
func CardsStatus(v *vault.Vault) ([]CardStatus, error) {
|
||||
cards, err := readCards(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blocks, err := readCardBlocks(v)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
status := make([]CardStatus, 0, len(cards))
|
||||
for _, c := range cards {
|
||||
entry := CardStatus{Last4: cardTail(c), Usable: true}
|
||||
if problem := validateCard(c); problem != nil {
|
||||
entry.Usable = false
|
||||
entry.Problem = problem.Error()
|
||||
}
|
||||
if block, ok := blocks[cardFingerprint(c)]; ok {
|
||||
entry.Blocked = block.Reason
|
||||
if remaining := block.Until - time.Now().Unix(); block.Until > 0 && remaining > 0 {
|
||||
entry.CoolingSeconds = remaining
|
||||
}
|
||||
}
|
||||
status = append(status, entry)
|
||||
}
|
||||
return status, nil
|
||||
}
|
||||
|
||||
// AddCardRecords appends cards from a JSON object or array. Missing billing
|
||||
// fields are inherited from an existing card because cardholders normally keep
|
||||
// one billing profile. Duplicate numbers replace the existing entry.
|
||||
func AddCardRecords(v *vault.Vault, raw []byte) (int, error) {
|
||||
incoming, err := decodeCardInput(raw)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
cards, err := readCardsOptional(v)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return mergeCards(v, cards, incoming, true)
|
||||
}
|
||||
|
||||
// SetCardRecords replaces the whole card set with a validated JSON array.
|
||||
func SetCardRecords(v *vault.Vault, raw []byte) (int, error) {
|
||||
incoming, err := decodeCardInput(raw)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return mergeCards(v, nil, incoming, false)
|
||||
}
|
||||
|
||||
func decodeCardInput(raw []byte) ([]card, error) {
|
||||
trimmed := strings.TrimSpace(string(raw))
|
||||
if trimmed == "" {
|
||||
return nil, errors.New("stdin must contain a card object or a JSON array of cards")
|
||||
}
|
||||
var many []card
|
||||
if strings.HasPrefix(trimmed, "[") {
|
||||
if json.Unmarshal(raw, &many) != nil {
|
||||
return nil, errors.New("stdin must be a valid JSON array of cards")
|
||||
}
|
||||
} else {
|
||||
var one card
|
||||
if json.Unmarshal(raw, &one) != nil {
|
||||
return nil, errors.New("stdin must be a valid card object")
|
||||
}
|
||||
many = []card{one}
|
||||
}
|
||||
if len(many) == 0 {
|
||||
return nil, errors.New("no cards supplied")
|
||||
}
|
||||
return many, nil
|
||||
}
|
||||
|
||||
func mergeCards(v *vault.Vault, existing, incoming []card, inherit bool) (int, error) {
|
||||
base := card{}
|
||||
for _, c := range existing {
|
||||
if validateCard(c) == nil {
|
||||
base = c
|
||||
break
|
||||
}
|
||||
}
|
||||
merged := append([]card{}, existing...)
|
||||
for _, c := range incoming {
|
||||
if inherit {
|
||||
c = inheritBilling(c, base)
|
||||
}
|
||||
if err := validateCard(c); err != nil {
|
||||
return 0, fmt.Errorf("card ending %s: %w", cardTail(c), err)
|
||||
}
|
||||
replaced := false
|
||||
for i := range merged {
|
||||
if merged[i].Number == c.Number {
|
||||
merged[i] = c
|
||||
replaced = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !replaced {
|
||||
merged = append(merged, c)
|
||||
}
|
||||
}
|
||||
if len(merged) == 0 {
|
||||
return 0, errors.New("card set would be empty")
|
||||
}
|
||||
b, err := json.Marshal(merged)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer clear(b)
|
||||
if err = v.Put(cardsRecord, b); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(merged), nil
|
||||
}
|
||||
|
||||
func inheritBilling(c card, base card) card {
|
||||
for _, field := range []struct {
|
||||
value *string
|
||||
base string
|
||||
}{
|
||||
{&c.Name, base.Name},
|
||||
{&c.Email, base.Email},
|
||||
{&c.Country, base.Country},
|
||||
{&c.Postal, base.Postal},
|
||||
{&c.Line1, base.Line1},
|
||||
{&c.Line2, base.Line2},
|
||||
{&c.City, base.City},
|
||||
{&c.State, base.State},
|
||||
} {
|
||||
if strings.TrimSpace(*field.value) == "" {
|
||||
*field.value = field.base
|
||||
}
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
||||
// RemoveCardRecord deletes the card ending in the given last four digits.
|
||||
func RemoveCardRecord(v *vault.Vault, last4 string) (int, error) {
|
||||
if !regexp.MustCompile(`^[0-9]{4}$`).MatchString(last4) {
|
||||
return 0, errors.New("--last4 must be exactly four digits")
|
||||
}
|
||||
cards, err := readCards(v)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
matches := 0
|
||||
kept := make([]card, 0, len(cards))
|
||||
for _, c := range cards {
|
||||
if cardTail(c) == last4 {
|
||||
matches++
|
||||
continue
|
||||
}
|
||||
kept = append(kept, c)
|
||||
}
|
||||
if matches == 0 {
|
||||
return 0, fmt.Errorf("no configured card ends with %s", last4)
|
||||
}
|
||||
if matches > 1 {
|
||||
return 0, errors.New("more than one configured card ends with those digits; remove it from the JSON set instead")
|
||||
}
|
||||
if len(kept) == 0 {
|
||||
return 0, errors.New("refusing to remove the last payment card")
|
||||
}
|
||||
b, err := json.Marshal(kept)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer clear(b)
|
||||
if err = v.Put(cardsRecord, b); err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return len(kept), nil
|
||||
}
|
||||
|
||||
// UpdateCardBilling applies billing fields to every configured card.
|
||||
func UpdateCardBilling(v *vault.Vault, fields map[string]string) (int, error) {
|
||||
allowed := map[string]bool{"billing_name": true, "email": true, "billing_country": true, "billing_postal_code": true, "billing_address_line1": true, "billing_address_line2": true, "billing_city": true, "billing_state": true}
|
||||
for name := range fields {
|
||||
if !allowed[name] {
|
||||
return 0, errors.New("unsupported billing field")
|
||||
}
|
||||
}
|
||||
cards, err := readCards(v)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
updated := make([]card, 0, len(cards))
|
||||
for _, c := range cards {
|
||||
raw, err := json.Marshal(c)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer clear(raw)
|
||||
var record map[string]any
|
||||
if json.Unmarshal(raw, &record) != nil {
|
||||
return 0, errors.New("invalid card record")
|
||||
}
|
||||
for name, value := range fields {
|
||||
record[name] = value
|
||||
}
|
||||
out, err := json.Marshal(record)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer clear(out)
|
||||
var next card
|
||||
if json.Unmarshal(out, &next) != nil {
|
||||
return 0, errors.New("invalid card record after billing update")
|
||||
}
|
||||
if err = validateCard(next); err != nil {
|
||||
return 0, fmt.Errorf("card ending %s: %w", cardTail(next), err)
|
||||
}
|
||||
updated = append(updated, next)
|
||||
}
|
||||
b, err := json.Marshal(updated)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
defer clear(b)
|
||||
if _, err = v.Get(cardsRecord); err == nil {
|
||||
return len(updated), v.Put(cardsRecord, b)
|
||||
} else if !errors.Is(err, sql.ErrNoRows) {
|
||||
return 0, err
|
||||
}
|
||||
return len(updated), v.Put(legacyCardKey, b)
|
||||
}
|
||||
|
||||
// RotationInfo is a number-free view of the running card+node batch for the CLI.
|
||||
type RotationInfo struct {
|
||||
BatchSize int `json:"batch_size"`
|
||||
Used int `json:"used"`
|
||||
CardLast4 string `json:"card_last4,omitempty"`
|
||||
Node string `json:"node,omitempty"`
|
||||
Cards int `json:"cards"`
|
||||
Usable int `json:"usable"`
|
||||
Blocked []string `json:"blocked,omitempty"`
|
||||
Cooling []string `json:"cooling,omitempty"`
|
||||
}
|
||||
|
||||
func PaymentRotationStatus(v *vault.Vault) (RotationInfo, error) {
|
||||
cards, err := readCards(v)
|
||||
if err != nil {
|
||||
return RotationInfo{}, err
|
||||
}
|
||||
blocks, err := readCardBlocks(v)
|
||||
if err != nil {
|
||||
return RotationInfo{}, err
|
||||
}
|
||||
info := RotationInfo{BatchSize: PaymentBatchSize, Cards: len(cards)}
|
||||
for _, c := range cards {
|
||||
if validateCard(c) == nil {
|
||||
info.Usable++
|
||||
}
|
||||
if block, ok := blocks[cardFingerprint(c)]; ok {
|
||||
if block.Until > time.Now().Unix() {
|
||||
info.Cooling = append(info.Cooling, fmt.Sprintf("%s (%s)", cardTail(c), block.Reason))
|
||||
} else if block.Until == 0 {
|
||||
info.Blocked = append(info.Blocked, cardTail(c)+" ("+block.Reason+")")
|
||||
}
|
||||
}
|
||||
}
|
||||
rotation, err := readPaymentRotation(v)
|
||||
if err != nil {
|
||||
return RotationInfo{}, err
|
||||
}
|
||||
if rotation == nil {
|
||||
return info, nil
|
||||
}
|
||||
info.Used = rotation.Used
|
||||
if c, ok := cardByFingerprint(cards, rotation.CardFingerprint); ok {
|
||||
info.CardLast4 = cardTail(c)
|
||||
}
|
||||
if len(rotation.Outbound) > 0 {
|
||||
if routeGroup(rotation.Outbound) == "direct" {
|
||||
info.Node = "direct"
|
||||
} else {
|
||||
info.Node = "node-" + rotation.NodeID[:12]
|
||||
}
|
||||
}
|
||||
return info, nil
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package checkout
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const (
|
||||
testCardOne = `{"number":"4242424242424242","exp_month":"12","exp_year":"2099","cvc":"123","billing_name":"Test Holder","email":"holder@example.invalid","billing_country":"US"}`
|
||||
testCardTwo = `{"number":"4000056655665556","exp_month":"11","exp_year":"2099","cvc":"456","billing_name":"Test Holder","email":"holder@example.invalid","billing_country":"US"}`
|
||||
testCardThree = `{"number":"5555555555554444","exp_month":"10","exp_year":"2099","cvc":"789","billing_name":"Test Holder","email":"holder@example.invalid","billing_country":"US"}`
|
||||
)
|
||||
|
||||
func TestReadCardsPrefersSetAndFallsBackToLegacy(t *testing.T) {
|
||||
v := controlFixture(t)
|
||||
if err := v.Put("card", []byte(testCardOne)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cards, err := readCards(v)
|
||||
if err != nil || len(cards) != 1 || cards[0].Number != "4242424242424242" {
|
||||
t.Fatalf("legacy fallback failed: %+v %v", cards, err)
|
||||
}
|
||||
if n, err := AddCardRecords(v, []byte(testCardTwo)); err != nil || n != 2 {
|
||||
t.Fatalf("add failed: %d %v", n, err)
|
||||
}
|
||||
if n, err := AddCardRecords(v, []byte("["+testCardThree+"]")); err != nil || n != 3 {
|
||||
t.Fatalf("append failed: %d %v", n, err)
|
||||
}
|
||||
cards, err = readCards(v)
|
||||
if err != nil || len(cards) != 3 {
|
||||
t.Fatalf("set not preferred: %+v %v", cards, err)
|
||||
}
|
||||
if cards[1].Name != "Test Holder" || cards[1].Country != "US" {
|
||||
t.Fatal("billing was not inherited")
|
||||
}
|
||||
// Re-adding an existing number replaces it instead of duplicating.
|
||||
if n, err := AddCardRecords(v, []byte(strings.Replace(testCardTwo, `"456"`, `"999"`, 1))); err != nil || n != 3 {
|
||||
t.Fatalf("duplicate replacement failed: %d %v", n, err)
|
||||
}
|
||||
cards, _ = readCards(v)
|
||||
if cards[1].CVC != "999" {
|
||||
t.Fatal("duplicate card was not updated")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCardValidationAndExpiryAreEnforced(t *testing.T) {
|
||||
v := controlFixture(t)
|
||||
if _, err := AddCardRecords(v, []byte(`{"number":"4242424242424243","exp_month":"12","exp_year":"2099","cvc":"123","billing_name":"N","email":"a@b.invalid","billing_country":"US"}`)); err == nil {
|
||||
t.Fatal("bad checksum accepted")
|
||||
}
|
||||
if _, err := AddCardRecords(v, []byte(`{"number":"4242424242424242","exp_month":"01","exp_year":"2000","cvc":"123","billing_name":"N","email":"a@b.invalid","billing_country":"US"}`)); err == nil {
|
||||
t.Fatal("expired card accepted")
|
||||
}
|
||||
if _, err := AddCardRecords(v, []byte(testCardOne)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// A second card without billing inherits the first profile.
|
||||
if _, err := AddCardRecords(v, []byte(`{"number":"4000056655665556","exp_month":"11","exp_year":"2099","cvc":"456"}`)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
status, err := CardsStatus(v)
|
||||
if err != nil || len(status) != 2 || !status[0].Usable || !status[1].Usable {
|
||||
t.Fatalf("status=%+v err=%v", status, err)
|
||||
}
|
||||
if _, err = RemoveCardRecord(v, "5556"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err = RemoveCardRecord(v, "4242"); err == nil {
|
||||
t.Fatal("removing the last card was allowed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetCardRecordsReplacesAndRejectsEmpty(t *testing.T) {
|
||||
v := controlFixture(t)
|
||||
if _, err := v.Get(cardsRecord); err == nil {
|
||||
t.Fatal("unexpected card set fixture")
|
||||
}
|
||||
if _, err := SetCardRecords(v, []byte(`[]`)); err == nil {
|
||||
t.Fatal("empty set accepted")
|
||||
}
|
||||
if n, err := SetCardRecords(v, []byte("["+testCardOne+","+testCardTwo+"]")); err != nil || n != 2 {
|
||||
t.Fatalf("set failed: %d %v", n, err)
|
||||
}
|
||||
rotation, err := PaymentRotationStatus(v)
|
||||
if err != nil || rotation.Cards != 2 || rotation.Usable != 2 || rotation.BatchSize != PaymentBatchSize {
|
||||
t.Fatalf("status=%+v err=%v", rotation, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCardSetFingerprintTracksMembershipNotOrder(t *testing.T) {
|
||||
v := controlFixture(t)
|
||||
if _, err := SetCardRecords(v, []byte("["+testCardOne+","+testCardTwo+"]")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
before, err := paymentCardFingerprint(v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err = SetCardRecords(v, []byte("["+testCardTwo+","+testCardOne+"]")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
after, _ := paymentCardFingerprint(v)
|
||||
if before != after {
|
||||
t.Fatal("set fingerprint changed when only order changed")
|
||||
}
|
||||
if _, err = AddCardRecords(v, []byte(testCardThree)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
changed, _ := paymentCardFingerprint(v)
|
||||
if changed == before {
|
||||
t.Fatal("set fingerprint did not change after adding a card")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBlockedCardsAreSkippedUntilExplicitlyUnblocked(t *testing.T) {
|
||||
v := controlFixture(t)
|
||||
if _, err := SetCardRecords(v, []byte("["+testCardOne+","+testCardTwo+","+testCardThree+"]")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
cards, _ := readCards(v)
|
||||
first := cardFingerprint(cards[0])
|
||||
second := cardFingerprint(cards[1])
|
||||
if err := blockPaymentCard(v, first, "do_not_try_again"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := blockPaymentCard(v, second, "do_not_try_again"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if usable, err := hasUsableCard(v); err != nil || !usable {
|
||||
t.Fatal("third card should remain usable")
|
||||
}
|
||||
pair, _, err := choosePaymentPair(v, cards, nil, "", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if cardFingerprint(pair) != cardFingerprint(cards[2]) {
|
||||
t.Fatal("blocked card was selected")
|
||||
}
|
||||
if err := blockPaymentCard(v, cardFingerprint(cards[2]), "do_not_try_again"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if usable, _ := hasUsableCard(v); usable {
|
||||
t.Fatal("all cards blocked but still reported usable")
|
||||
}
|
||||
if _, _, err := choosePaymentPair(v, cards, nil, "", ""); err != ErrNoUsableCard {
|
||||
t.Fatalf("err=%v", err)
|
||||
}
|
||||
if cleared, err := UnblockPaymentCards(v); err != nil || cleared != 3 {
|
||||
t.Fatalf("cleared=%d err=%v", cleared, err)
|
||||
}
|
||||
if usable, _ := hasUsableCard(v); !usable {
|
||||
t.Fatal("unblock did not restore rotation")
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ type Record struct {
|
||||
CreationAttempts int `json:"creation_attempts,omitempty"`
|
||||
PreflightSaved bool `json:"preflight_saved,omitempty"`
|
||||
PaymentMethod string `json:"payment_method,omitempty"`
|
||||
CardFingerprint string `json:"card_fingerprint,omitempty"`
|
||||
ConfirmParameters string `json:"confirm_parameters,omitempty"`
|
||||
ConfirmKey string `json:"confirm_key,omitempty"`
|
||||
SubmittedAt int64 `json:"submitted_at,omitempty"`
|
||||
@@ -180,7 +181,11 @@ func run(ctx context.Context, v *vault.Vault, user, expectedRecipient string, pa
|
||||
return &r, e
|
||||
}
|
||||
}
|
||||
s, e := newStripe(ctx, v, r.RecipientID)
|
||||
paymentFlow := paymentRead
|
||||
if pay {
|
||||
paymentFlow = paymentPay
|
||||
}
|
||||
s, e := newStripe(ctx, v, r.RecipientID, paymentFlow)
|
||||
if e != nil {
|
||||
return &r, e
|
||||
}
|
||||
@@ -203,13 +208,19 @@ func run(ctx context.Context, v *vault.Vault, user, expectedRecipient string, pa
|
||||
if !pay {
|
||||
return &r, nil
|
||||
}
|
||||
c, e := readCard(v)
|
||||
c, e := s.paymentCard()
|
||||
if e != nil {
|
||||
return &r, e
|
||||
}
|
||||
r.CardFingerprint = cardFingerprint(c)
|
||||
progress(ctx, 70, "正在准备付款,请勿重复提交…")
|
||||
method, e := s.tokenize(ctx, &r, c)
|
||||
if e != nil {
|
||||
if cardTokenizationRejected(e) {
|
||||
// The card itself was rejected before any submit: end the batch so the
|
||||
// next attempt rotates to another card instead of retrying this one.
|
||||
_ = markPaymentDecline(v, r.RecipientID)
|
||||
}
|
||||
return &r, e
|
||||
}
|
||||
// Refresh after card creation; confirmation also pins the expected amount server-side.
|
||||
|
||||
@@ -56,7 +56,7 @@ func inspect(ctx context.Context, v *vault.Vault, user string, port, months int,
|
||||
if !sessionURL(r.URL, r.SessionID) {
|
||||
return errors.New("untrusted recorded checkout")
|
||||
}
|
||||
s, e := newStripe(ctx, v, r.RecipientID)
|
||||
s, e := newStripe(ctx, v, r.RecipientID, paymentRead)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
|
||||
@@ -12,14 +12,24 @@ import (
|
||||
"xgift/internal/vault"
|
||||
)
|
||||
|
||||
// CardSummary exposes only a display suffix and an opaque configuration binding.
|
||||
func CardSummary(v *vault.Vault) (last4, binding string, err error) {
|
||||
c, err := readCard(v)
|
||||
// CardSummary exposes only a display suffix, the configured card count and an
|
||||
// opaque set binding. Rotation inside the same set does not change the binding.
|
||||
func CardSummary(v *vault.Vault) (last4 string, count int, binding string, err error) {
|
||||
cards, err := readCards(v)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
return "", 0, "", err
|
||||
}
|
||||
binding, err = paymentCardFingerprint(v)
|
||||
return c.Number[len(c.Number)-4:], binding, err
|
||||
usable := usableCards(cards)
|
||||
if len(usable) == 0 {
|
||||
return "", len(cards), "", ErrNoUsableCard
|
||||
}
|
||||
display := usable[0]
|
||||
if rotation, e := readPaymentRotation(v); e == nil && rotation != nil && rotation.CardFingerprint != "" {
|
||||
if c, ok := cardByFingerprint(cards, rotation.CardFingerprint); ok && validateCard(c) == nil {
|
||||
display = c
|
||||
}
|
||||
}
|
||||
return cardTail(display), len(cards), cardSetFingerprint(cards), nil
|
||||
}
|
||||
|
||||
// ManualRetryBlocked deliberately treats bank instructions as a stop condition.
|
||||
@@ -145,7 +155,7 @@ func ManualRecoverForRecipient(ctx context.Context, v *vault.Vault, user, recipi
|
||||
if err = verifySubmission(v, &r, plan); err != nil {
|
||||
return &r, err
|
||||
}
|
||||
s, err := newStripe(ctx, v, r.RecipientID)
|
||||
s, err := newStripe(ctx, v, r.RecipientID, paymentRetry)
|
||||
if err != nil {
|
||||
return &r, err
|
||||
}
|
||||
@@ -204,14 +214,18 @@ func manualRecoverDeclined(ctx context.Context, v *vault.Vault, r *Record, s *st
|
||||
if err = v.Put(fmt.Sprintf("manual-previous:%s:%d", r.SessionID, next.RecoveryAttempts), old); err != nil {
|
||||
return r, err
|
||||
}
|
||||
c, err := readCard(v)
|
||||
c, err := s.paymentCard()
|
||||
if err != nil {
|
||||
return r, err
|
||||
}
|
||||
method, err := s.tokenize(ctx, &next, c)
|
||||
if err != nil {
|
||||
if cardTokenizationRejected(err) {
|
||||
_ = markPaymentDecline(v, r.RecipientID)
|
||||
}
|
||||
return r, err
|
||||
}
|
||||
next.CardFingerprint = cardFingerprint(c)
|
||||
page, proof, err := s.manualPreflight(ctx, r, plan)
|
||||
if err != nil {
|
||||
return r, err
|
||||
@@ -261,6 +275,8 @@ func ManualRecoveryErrorMessage(err error) string {
|
||||
return replacementMessage(err)
|
||||
case errors.Is(err, ErrPaymentPaused):
|
||||
return "银行卡付款保护已暂停,未继续提交。"
|
||||
case errors.Is(err, ErrNoUsableCard):
|
||||
return "没有可用的付款卡(可能全部在冷却或被封锁),未提交补单付款;请用 cards list 查看卡池状态。"
|
||||
case strings.Contains(text, "checkout_not_active_session"):
|
||||
return "原账单已失效,未提交补单付款;需要单独核实。"
|
||||
case strings.Contains(text, "unpaid"), strings.Contains(text, "payment intent"), strings.Contains(text, "payment_intent"):
|
||||
|
||||
@@ -2,9 +2,7 @@ package checkout
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"database/sql"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
@@ -53,12 +51,11 @@ func readPaymentControl(v *vault.Vault) (paymentControl, error) {
|
||||
return state, nil
|
||||
}
|
||||
func paymentCardFingerprint(v *vault.Vault) (string, error) {
|
||||
c, err := readCard(v)
|
||||
cards, err := readCards(v)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
digest := sha256.Sum256([]byte(c.Number + ":" + c.Month + ":" + c.Year))
|
||||
return hex.EncodeToString(digest[:]), nil
|
||||
return cardSetFingerprint(cards), nil
|
||||
}
|
||||
func savePaymentControl(v *vault.Vault, state paymentControl) error {
|
||||
b, err := json.Marshal(state)
|
||||
@@ -138,17 +135,49 @@ func paymentOutcome(v *vault.Vault, r *Record) error {
|
||||
} else if IsPaymentDeclined(r) {
|
||||
state.ConsecutiveDeclines++
|
||||
state.Outcome = "declined"
|
||||
// The declined order keeps its evidence; the running card+node batch is
|
||||
// expired so the next attempt rotates to another pair.
|
||||
if err = markPaymentDecline(v, r.RecipientID); err != nil {
|
||||
return err
|
||||
}
|
||||
// Ordinary card declines stay local to the failed order. Only an explicit
|
||||
// provider instruction pauses this card globally.
|
||||
// provider no-retry instruction blocks that one card; with other cards
|
||||
// configured the site keeps paying through the remaining rotation and
|
||||
// pauses only when there is nothing left to try.
|
||||
if r.LastError != nil && r.LastError.AdviceCode == "do_not_try_again" {
|
||||
state.Paused = true
|
||||
state.Reason = "do_not_try_again"
|
||||
fingerprint := declinedCardFingerprint(v, r.RecipientID)
|
||||
if fingerprint == "" {
|
||||
state.Paused = true
|
||||
state.Reason = "do_not_try_again"
|
||||
} else {
|
||||
if err = blockPaymentCard(v, fingerprint, "do_not_try_again"); err != nil {
|
||||
return err
|
||||
}
|
||||
remaining, e := hasUsableCard(v)
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
if !remaining {
|
||||
state.Paused = true
|
||||
state.Reason = "do_not_try_again"
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return nil
|
||||
}
|
||||
return savePaymentControl(v, state)
|
||||
}
|
||||
|
||||
// declinedCardFingerprint resolves the card bound to a declined order without
|
||||
// selecting, rotating or contacting any node.
|
||||
func declinedCardFingerprint(v *vault.Vault, recipient string) string {
|
||||
route, err := readPaymentRoute(v, recipient)
|
||||
if err != nil || route.Card == "" {
|
||||
return ""
|
||||
}
|
||||
return route.Card
|
||||
}
|
||||
func IsPaymentDeclined(r *Record) bool {
|
||||
return r != nil && r.Status != "succeeded" && r.Status != "requires_action" && (r.Status == "declined" || r.LastError != nil && r.LastError.HTTP == 402 && r.LastError.Type == "card_error")
|
||||
}
|
||||
|
||||
@@ -211,7 +211,7 @@ func TestNoAvailableExitAndCanceledRequestDoNotReplay(t *testing.T) {
|
||||
raw := `[{"type":"direct","tag":"direct"}]`
|
||||
v.Put("payment-outbounds", []byte(raw))
|
||||
v.Put("stripe-key", []byte("pk_live_Test"))
|
||||
s, e := newStripe(context.Background(), v, "1234")
|
||||
s, e := newStripe(context.Background(), v, "1234", paymentRead)
|
||||
if e != nil {
|
||||
t.Fatal(e)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,396 @@
|
||||
package checkout
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"math/big"
|
||||
"regexp"
|
||||
"time"
|
||||
"xgift/internal/proxy"
|
||||
"xgift/internal/vault"
|
||||
)
|
||||
|
||||
// PaymentBatchSize is how many consecutive payment attempts share one card+node
|
||||
// pair. A decline ends the batch immediately and the next attempt rotates.
|
||||
const PaymentBatchSize = 3
|
||||
|
||||
const paymentRotationRecord = "payment-rotation"
|
||||
|
||||
type paymentRotation struct {
|
||||
CardFingerprint string `json:"card_fingerprint,omitempty"`
|
||||
NodeID string `json:"node_id,omitempty"`
|
||||
Outbound json.RawMessage `json:"outbound,omitempty"`
|
||||
Used int `json:"used"`
|
||||
UpdatedAt int64 `json:"updated_at"`
|
||||
}
|
||||
|
||||
func readPaymentRotation(v *vault.Vault) (*paymentRotation, error) {
|
||||
raw, err := v.Get(paymentRotationRecord)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer clear(raw)
|
||||
var r paymentRotation
|
||||
if json.Unmarshal(raw, &r) != nil || r.Used < 0 || r.Used > PaymentBatchSize {
|
||||
return nil, errors.New("invalid payment rotation record")
|
||||
}
|
||||
if len(r.Outbound) > 0 {
|
||||
if _, err = proxy.ParseOutboundPool(append(append([]byte{'['}, r.Outbound...), ']')); err != nil {
|
||||
return nil, errors.New("invalid payment rotation outbound")
|
||||
}
|
||||
if r.NodeID != outboundID(r.Outbound) {
|
||||
return nil, errors.New("payment rotation node does not match its snapshot")
|
||||
}
|
||||
}
|
||||
return &r, nil
|
||||
}
|
||||
|
||||
func savePaymentRotation(v *vault.Vault, r *paymentRotation) error {
|
||||
r.UpdatedAt = time.Now().Unix()
|
||||
b, err := json.Marshal(r)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer clear(b)
|
||||
return v.Put(paymentRotationRecord, b)
|
||||
}
|
||||
|
||||
// ResetPaymentRotation expires the running batch so the next payment attempt
|
||||
// selects a fresh card+node pair.
|
||||
func ResetPaymentRotation(v *vault.Vault) error {
|
||||
paymentRouteMu.Lock()
|
||||
defer paymentRouteMu.Unlock()
|
||||
rotation, err := readPaymentRotation(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rotation == nil {
|
||||
rotation = &paymentRotation{}
|
||||
}
|
||||
rotation.Used = PaymentBatchSize
|
||||
return savePaymentRotation(v, rotation)
|
||||
}
|
||||
|
||||
// choosePaymentPair picks one random usable card and one random available node.
|
||||
// Cards that are blocked or cooling are skipped; keepCard pins the running
|
||||
// batch to its card; forbidden replaces the given node when possible.
|
||||
func choosePaymentPair(v *vault.Vault, cards []card, nodes []json.RawMessage, keepCard, forbidden string) (card, json.RawMessage, error) {
|
||||
blocks, err := readCardBlocks(v)
|
||||
if err != nil {
|
||||
return card{}, nil, err
|
||||
}
|
||||
usable := make([]card, 0, len(cards))
|
||||
for _, c := range cards {
|
||||
if validateCard(c) != nil {
|
||||
continue
|
||||
}
|
||||
if _, blocked := blocks[cardFingerprint(c)]; blocked {
|
||||
continue
|
||||
}
|
||||
usable = append(usable, c)
|
||||
}
|
||||
if len(usable) == 0 {
|
||||
return card{}, nil, ErrNoUsableCard
|
||||
}
|
||||
pickable := usable
|
||||
if keepCard != "" {
|
||||
for _, c := range usable {
|
||||
if cardFingerprint(c) == keepCard {
|
||||
pickable = []card{c}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// New batches prefer the usable card that has gone unused the longest, so a
|
||||
// two-card set alternates instead of streaking by chance.
|
||||
if keepCard == "" {
|
||||
usage, err := readCardUsage(v)
|
||||
if err != nil {
|
||||
return card{}, nil, err
|
||||
}
|
||||
oldest := int64(-1)
|
||||
preferred := make([]card, 0, len(pickable))
|
||||
for _, c := range pickable {
|
||||
used := usage[cardFingerprint(c)]
|
||||
if oldest < 0 || used < oldest {
|
||||
oldest = used
|
||||
preferred = append(preferred[:0], c)
|
||||
} else if used == oldest {
|
||||
preferred = append(preferred, c)
|
||||
}
|
||||
}
|
||||
pickable = preferred
|
||||
}
|
||||
cardIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(pickable))))
|
||||
if err != nil {
|
||||
return card{}, nil, errors.New("cannot choose payment card")
|
||||
}
|
||||
chosen := pickable[cardIndex.Int64()]
|
||||
|
||||
if len(nodes) == 0 {
|
||||
return chosen, json.RawMessage(`{"type":"direct","tag":"direct"}`), nil
|
||||
}
|
||||
available, err := availablePaymentNodes(v, nodes)
|
||||
if err != nil {
|
||||
return card{}, nil, err
|
||||
}
|
||||
if len(available) == 0 {
|
||||
return card{}, nil, ErrPaymentNodesCooling
|
||||
}
|
||||
choices := available
|
||||
if last, e := v.Get("stripe-route:last-node"); e == nil && len(last) > 0 {
|
||||
lastGroup := ""
|
||||
for _, node := range nodes {
|
||||
if outboundID(node) == string(last) {
|
||||
lastGroup = routeGroup(node)
|
||||
break
|
||||
}
|
||||
}
|
||||
clear(last)
|
||||
if lastGroup != "" {
|
||||
filtered := make([]json.RawMessage, 0, len(choices))
|
||||
for _, node := range choices {
|
||||
if routeGroup(node) != lastGroup {
|
||||
filtered = append(filtered, node)
|
||||
}
|
||||
}
|
||||
if len(filtered) > 0 {
|
||||
choices = filtered
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(choices) > 1 && forbidden != "" {
|
||||
filtered := make([]json.RawMessage, 0, len(choices))
|
||||
for _, node := range choices {
|
||||
if outboundID(node) != forbidden {
|
||||
filtered = append(filtered, node)
|
||||
}
|
||||
}
|
||||
if len(filtered) > 0 {
|
||||
choices = filtered
|
||||
}
|
||||
}
|
||||
nodeIndex, err := rand.Int(rand.Reader, big.NewInt(int64(len(choices))))
|
||||
if err != nil {
|
||||
return card{}, nil, errors.New("cannot choose payment node")
|
||||
}
|
||||
return chosen, choices[nodeIndex.Int64()], nil
|
||||
}
|
||||
|
||||
func paymentNodes(v *vault.Vault) ([]json.RawMessage, error) {
|
||||
raw, err := v.Get("payment-outbounds")
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer clear(raw)
|
||||
return proxy.ParseOutboundPool(raw)
|
||||
}
|
||||
|
||||
// continueOrRotate returns the pair the next payment attempt should use. A
|
||||
// running batch of fewer than PaymentBatchSize attempts keeps its card; a new
|
||||
// batch prefers a different node.
|
||||
func continueOrRotate(v *vault.Vault, cards []card, nodes []json.RawMessage, rotation *paymentRotation, continueBatch bool, forbidden string) (card, json.RawMessage, int, error) {
|
||||
if continueBatch && rotation != nil && rotation.Used < PaymentBatchSize && rotation.CardFingerprint != "" {
|
||||
c, ok := cardByFingerprint(cards, rotation.CardFingerprint)
|
||||
if ok && validateCard(c) == nil {
|
||||
if blocked, e := paymentCardBlocked(v, rotation.CardFingerprint); e != nil {
|
||||
return card{}, nil, 0, e
|
||||
} else if !blocked {
|
||||
if len(rotation.Outbound) == 0 {
|
||||
return c, json.RawMessage(`{"type":"direct","tag":"direct"}`), rotation.Used + 1, nil
|
||||
}
|
||||
until, e := nodeCoolingUntil(v, rotation.Outbound)
|
||||
if e != nil {
|
||||
return card{}, nil, 0, e
|
||||
}
|
||||
if until <= time.Now().Unix() {
|
||||
return c, rotation.Outbound, rotation.Used + 1, nil
|
||||
}
|
||||
next, node, e := choosePaymentPair(v, cards, nodes, rotation.CardFingerprint, rotation.NodeID)
|
||||
if e != nil {
|
||||
return card{}, nil, 0, e
|
||||
}
|
||||
return next, node, rotation.Used + 1, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
chosen, node, err := choosePaymentPair(v, cards, nodes, "", forbidden)
|
||||
if err != nil {
|
||||
return card{}, nil, 0, err
|
||||
}
|
||||
return chosen, node, 1, nil
|
||||
}
|
||||
|
||||
// assignPaymentRoute pins the card+node pair a payment submission must use and
|
||||
// records it on the order. rotate forces a fresh pair (used after a decline).
|
||||
// Read-only Stripe calls keep using selectPaymentRoute and never rotate cards.
|
||||
func assignPaymentRoute(v *vault.Vault, recipient string, rotate bool) (*paymentRoute, card, error) {
|
||||
if !regexp.MustCompile(`^[0-9]{1,32}$`).MatchString(recipient) {
|
||||
return nil, card{}, errors.New("payment route requires a bound recipient")
|
||||
}
|
||||
paymentRouteMu.Lock()
|
||||
defer paymentRouteMu.Unlock()
|
||||
cards, err := readCards(v)
|
||||
if err != nil {
|
||||
return nil, card{}, err
|
||||
}
|
||||
rotation, err := readPaymentRotation(v)
|
||||
if err != nil {
|
||||
return nil, card{}, err
|
||||
}
|
||||
nodes, err := paymentNodes(v)
|
||||
if err != nil {
|
||||
return nil, card{}, err
|
||||
}
|
||||
route, routeErr := readPaymentRoute(v, recipient)
|
||||
if routeErr != nil && !errors.Is(routeErr, sql.ErrNoRows) {
|
||||
return nil, card{}, routeErr
|
||||
}
|
||||
|
||||
var bound card
|
||||
boundOK := false
|
||||
if routeErr == nil && route.Card != "" {
|
||||
if c, ok := cardByFingerprint(cards, route.Card); ok && validateCard(c) == nil {
|
||||
blocked, e := paymentCardBlocked(v, route.Card)
|
||||
if e != nil {
|
||||
return nil, card{}, e
|
||||
}
|
||||
if !blocked {
|
||||
bound, boundOK = c, true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if routeErr == nil && !rotate && boundOK {
|
||||
// The order keeps its pinned pair; only a durable transport cooldown may
|
||||
// move the node, and the card always stays with the order.
|
||||
until, e := nodeCoolingUntil(v, route.Outbound)
|
||||
if e != nil {
|
||||
return nil, card{}, e
|
||||
}
|
||||
if until > time.Now().Unix() {
|
||||
next, e := rotateCoolingRouteLocked(v, route)
|
||||
if e != nil {
|
||||
return nil, card{}, e
|
||||
}
|
||||
return next, bound, nil
|
||||
}
|
||||
return route, bound, nil
|
||||
}
|
||||
|
||||
// A fresh pair is needed: first attempt, a route with no usable card, or an
|
||||
// explicit rotation after a decline. A retry keeps the rejected card out of
|
||||
// rotation for the cooldown.
|
||||
forbidden := ""
|
||||
if routeErr == nil {
|
||||
forbidden = route.NodeID
|
||||
}
|
||||
if rotate && routeErr == nil && route.Card != "" {
|
||||
if _, ok := cardByFingerprint(cards, route.Card); ok {
|
||||
if err = coolPaymentCardLocked(v, route.Card, "declined"); err != nil {
|
||||
return nil, card{}, err
|
||||
}
|
||||
}
|
||||
}
|
||||
continueBatch := !rotate
|
||||
chosen, node, used, err := continueOrRotate(v, cards, nodes, rotation, continueBatch, forbidden)
|
||||
if err != nil {
|
||||
return nil, card{}, err
|
||||
}
|
||||
fingerprint := cardFingerprint(chosen)
|
||||
next := &paymentRoute{Recipient: recipient, NodeID: outboundID(node), Outbound: node, Card: fingerprint, SelectedAt: time.Now().Unix()}
|
||||
b, err := json.Marshal(next)
|
||||
if err != nil {
|
||||
return nil, card{}, err
|
||||
}
|
||||
defer clear(b)
|
||||
if routeErr == nil {
|
||||
expected, e := v.Get("stripe-route:" + recipient)
|
||||
if e != nil {
|
||||
return nil, card{}, e
|
||||
}
|
||||
defer clear(expected)
|
||||
archive := "stripe-route-history:" + recipient + ":" + time.Now().Format("20060102T150405.000000000")
|
||||
if e = v.ReplaceArchived("stripe-route:"+recipient, archive, expected, expected, b); e != nil {
|
||||
return nil, card{}, e
|
||||
}
|
||||
} else {
|
||||
inserted, e := v.PutIfAbsent("stripe-route:"+recipient, b)
|
||||
if e != nil {
|
||||
return nil, card{}, e
|
||||
}
|
||||
if !inserted {
|
||||
// Another process bound this order first; keep that binding.
|
||||
current, e := readPaymentRoute(v, recipient)
|
||||
if e != nil {
|
||||
return nil, card{}, e
|
||||
}
|
||||
c, ok := cardByFingerprint(cards, current.Card)
|
||||
if !ok {
|
||||
usable := usableCards(cards)
|
||||
if len(usable) == 0 {
|
||||
return nil, card{}, ErrNoUsableCard
|
||||
}
|
||||
c = usable[0]
|
||||
}
|
||||
return current, c, nil
|
||||
}
|
||||
}
|
||||
if rotation == nil {
|
||||
rotation = &paymentRotation{}
|
||||
}
|
||||
rotation.CardFingerprint = fingerprint
|
||||
rotation.NodeID = next.NodeID
|
||||
rotation.Outbound = append(json.RawMessage(nil), node...)
|
||||
rotation.Used = used
|
||||
if err = savePaymentRotation(v, rotation); err != nil {
|
||||
return nil, card{}, err
|
||||
}
|
||||
if err = touchCardUsageLocked(v, fingerprint); err != nil {
|
||||
return nil, card{}, err
|
||||
}
|
||||
if err = v.Put("stripe-route:last-node", []byte(next.NodeID)); err != nil {
|
||||
return nil, card{}, err
|
||||
}
|
||||
return next, chosen, nil
|
||||
}
|
||||
|
||||
// markPaymentDecline ends the running batch and keeps the declined card out of
|
||||
// rotation for the cooldown while other cards remain available.
|
||||
func markPaymentDecline(v *vault.Vault, recipient string) error {
|
||||
if recipient == "" {
|
||||
return nil
|
||||
}
|
||||
paymentRouteMu.Lock()
|
||||
defer paymentRouteMu.Unlock()
|
||||
rotation, err := readPaymentRotation(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if rotation == nil {
|
||||
rotation = &paymentRotation{}
|
||||
}
|
||||
if route, e := readPaymentRoute(v, recipient); e == nil && route.Card != "" {
|
||||
if err = coolPaymentCardLocked(v, route.Card, "declined"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
rotation.Used = PaymentBatchSize
|
||||
return savePaymentRotation(v, rotation)
|
||||
}
|
||||
|
||||
// cardTokenizationRejected reports whether a failed card submission was
|
||||
// rejected by the provider because of the card itself rather than by a
|
||||
// transport or API problem. A rejected card is rotated away immediately.
|
||||
func cardTokenizationRejected(err error) bool {
|
||||
var se *stripeError
|
||||
return errors.As(err, &se) && se.Type == "card_error"
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
package checkout
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"xgift/internal/vault"
|
||||
)
|
||||
|
||||
// rotationSetup builds a vault with the given card records and the standard
|
||||
// two-server node pool used by the route tests.
|
||||
func rotationSetup(t *testing.T, cards ...string) *vault.Vault {
|
||||
t.Helper()
|
||||
v := controlFixture(t)
|
||||
if err := v.Put("payment-outbounds", []byte(twoPaymentNodes)); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := SetCardRecords(v, []byte("["+strings.Join(cards, ",")+"]")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return v
|
||||
}
|
||||
|
||||
func assignPair(t *testing.T, v *vault.Vault, recipient string, rotate bool) (string, string) {
|
||||
t.Helper()
|
||||
route, card, err := assignPaymentRoute(v, recipient, rotate)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return route.NodeID, cardFingerprint(card)
|
||||
}
|
||||
|
||||
func TestThreeConsecutiveOrdersShareOnePair(t *testing.T) {
|
||||
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
|
||||
firstNode, firstCard := assignPair(t, v, "101", false)
|
||||
secondNode, secondCard := assignPair(t, v, "102", false)
|
||||
thirdNode, thirdCard := assignPair(t, v, "103", false)
|
||||
if firstNode != secondNode || secondNode != thirdNode || firstCard != secondCard || secondCard != thirdCard {
|
||||
t.Fatalf("first three orders did not share one pair: %s/%s %s/%s %s/%s", firstNode, firstCard, secondNode, secondCard, thirdNode, thirdCard)
|
||||
}
|
||||
rotation, err := readPaymentRotation(v)
|
||||
if err != nil || rotation.Used != PaymentBatchSize {
|
||||
t.Fatalf("rotation=%+v err=%v", rotation, err)
|
||||
}
|
||||
fourthNode, _ := assignPair(t, v, "104", false)
|
||||
if fourthNode == thirdNode {
|
||||
t.Fatal("fourth order did not rotate to another pair")
|
||||
}
|
||||
rotation, _ = readPaymentRotation(v)
|
||||
if rotation.Used != 1 {
|
||||
t.Fatalf("new batch did not restart the counter: %+v", rotation)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeclineEndsBatchAndNextRotationAvoidsCard(t *testing.T) {
|
||||
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
|
||||
node, card := assignPair(t, v, "201", false)
|
||||
if err := markPaymentDecline(v, "201"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
rotation, err := readPaymentRotation(v)
|
||||
if err != nil || rotation.Used != PaymentBatchSize {
|
||||
t.Fatalf("decline was not recorded as a batch end: %+v %v", rotation, err)
|
||||
}
|
||||
if blocked, _ := paymentCardBlocked(v, card); !blocked {
|
||||
t.Fatal("declined card was not cooled down")
|
||||
}
|
||||
nextNode, nextCard := assignPair(t, v, "202", false)
|
||||
if nextCard == card {
|
||||
t.Fatal("next order reused the declined card")
|
||||
}
|
||||
if nextNode == node {
|
||||
t.Fatal("next order reused the declined node")
|
||||
}
|
||||
if _, err := readPaymentRotation(v); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRetryAfterDeclineRotatesPair(t *testing.T) {
|
||||
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
|
||||
node, card := assignPair(t, v, "301", false)
|
||||
next, nextCard, err := assignPaymentRoute(v, "301", true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if next.NodeID == node {
|
||||
t.Fatal("retry kept the rejected node")
|
||||
}
|
||||
if cardFingerprint(nextCard) == card {
|
||||
t.Fatal("retry reused the rejected card")
|
||||
}
|
||||
if next.Card != cardFingerprint(nextCard) {
|
||||
t.Fatal("retry route did not persist its card binding")
|
||||
}
|
||||
}
|
||||
|
||||
func TestRepeatAttemptKeepsBoundPairWithoutConsumingTwice(t *testing.T) {
|
||||
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
|
||||
node, card := assignPair(t, v, "401", false)
|
||||
again, againCard, err := assignPaymentRoute(v, "401", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if again.NodeID != node || cardFingerprint(againCard) != card {
|
||||
t.Fatal("repeat attempt did not keep its bound pair")
|
||||
}
|
||||
rotation, _ := readPaymentRotation(v)
|
||||
if rotation.Used != 1 {
|
||||
t.Fatalf("repeat attempt consumed another batch slot: %+v", rotation)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLegacyRouteAdoptsRunningBatchCard(t *testing.T) {
|
||||
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
|
||||
if _, err := selectPaymentRoute(v, "501"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, batchCard := assignPair(t, v, "502", false)
|
||||
next, card, err := assignPaymentRoute(v, "501", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if cardFingerprint(card) != batchCard {
|
||||
t.Fatal("legacy route did not adopt the running batch card")
|
||||
}
|
||||
if next.Card != batchCard {
|
||||
t.Fatal("card binding was not persisted on the legacy route")
|
||||
}
|
||||
rotation, _ := readPaymentRotation(v)
|
||||
if rotation.Used != 2 {
|
||||
t.Fatalf("legacy binding did not consume a batch slot: %+v", rotation)
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoolingBatchNodeMovesWithoutChangingCard(t *testing.T) {
|
||||
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
|
||||
nodeID, card := assignPair(t, v, "601", false)
|
||||
rotation, err := readPaymentRotation(v)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = coolPaymentNode(v, rotation.Outbound); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
nextNode, nextCard := assignPair(t, v, "602", false)
|
||||
if nextNode == nodeID {
|
||||
t.Fatal("cooling node was kept for the running batch")
|
||||
}
|
||||
if nextCard != card {
|
||||
t.Fatal("card changed during transport-failure node failover")
|
||||
}
|
||||
if rotation, _ = readPaymentRotation(v); rotation.Used != 2 {
|
||||
t.Fatalf("node failover did not consume exactly one slot: %+v", rotation)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEmptyPoolKeepsCardRotationOnDirect(t *testing.T) {
|
||||
v := controlFixture(t)
|
||||
if _, err := SetCardRecords(v, []byte("["+testCardOne+","+testCardTwo+"]")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
route, card, err := assignPaymentRoute(v, "701", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if routeGroup(route.Outbound) != "direct" || route.Card != cardFingerprint(card) {
|
||||
t.Fatalf("route=%+v", route)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDoNotTryAgainBlocksOneCardWithoutGlobalPause(t *testing.T) {
|
||||
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
|
||||
route, _, err := assignPaymentRoute(v, "801", false)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
declined := route.Card
|
||||
r := &Record{RecipientID: route.Recipient, SessionID: "cs_live_RotationOne", Status: "declined", LastError: &stripeError{HTTP: 402, Type: "card_error", AdviceCode: "do_not_try_again"}}
|
||||
if err = savePaymentControl(v, paymentControl{LastSession: r.SessionID}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = paymentOutcome(v, r); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if paused, _ := PaymentPaused(v); paused {
|
||||
t.Fatal("one blocked card paused rotation while two usable cards remain")
|
||||
}
|
||||
if blocked, _ := paymentCardBlocked(v, declined); !blocked {
|
||||
t.Fatal("declined card was not blocked")
|
||||
}
|
||||
cards, _ := readCards(v)
|
||||
for _, c := range cards {
|
||||
if cardFingerprint(c) != declined {
|
||||
if err = blockPaymentCard(v, cardFingerprint(c), "do_not_try_again"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
second := &Record{RecipientID: route.Recipient, SessionID: "cs_live_RotationTwo", Status: "declined", LastError: &stripeError{HTTP: 402, Type: "card_error", AdviceCode: "do_not_try_again"}}
|
||||
if err = savePaymentControl(v, paymentControl{LastSession: second.SessionID}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = paymentOutcome(v, second); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if paused, _ := PaymentPaused(v); !paused {
|
||||
t.Fatal("all cards blocked but the site stayed open")
|
||||
}
|
||||
if cleared, err := UnblockPaymentCards(v); err != nil || cleared != 3 {
|
||||
t.Fatalf("cleared=%d err=%v", cleared, err)
|
||||
}
|
||||
if paused, _ := PaymentPaused(v); paused {
|
||||
t.Fatal("explicit unblock did not lift the provider pause")
|
||||
}
|
||||
if usable, _ := hasUsableCard(v); !usable {
|
||||
t.Fatal("unblock did not restore rotation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCoolingCardReturnsAfterCooldown(t *testing.T) {
|
||||
v := rotationSetup(t, testCardOne, testCardTwo, testCardThree)
|
||||
cards, _ := readCards(v)
|
||||
first := cardFingerprint(cards[0])
|
||||
if err := coolPaymentCard(v, first, "declined"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if blocked, _ := paymentCardBlocked(v, first); !blocked {
|
||||
t.Fatal("cooled card still selectable")
|
||||
}
|
||||
blocks, _ := readCardBlocks(v)
|
||||
entry := blocks[first]
|
||||
entry.Until = time.Now().Add(-time.Second).Unix()
|
||||
blocks[first] = entry
|
||||
if err := saveCardBlocks(v, blocks); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if blocked, _ := paymentCardBlocked(v, first); blocked {
|
||||
t.Fatal("expired cooldown kept the card out of rotation")
|
||||
}
|
||||
if usable, _ := hasUsableCard(v); !usable {
|
||||
t.Fatal("expired cooldown broke the usable card set")
|
||||
}
|
||||
}
|
||||
|
||||
func TestTwoCardRotationAlternatesBatches(t *testing.T) {
|
||||
v := rotationSetup(t, testCardOne, testCardTwo)
|
||||
var batches []string
|
||||
for order := 0; order < 6; order++ {
|
||||
_, card := assignPair(t, v, fmt.Sprintf("81%d", order), false)
|
||||
batches = append(batches, card)
|
||||
}
|
||||
if batches[0] != batches[1] || batches[1] != batches[2] {
|
||||
t.Fatalf("first batch was not consistent: %v", batches)
|
||||
}
|
||||
if batches[3] != batches[4] || batches[4] != batches[5] {
|
||||
t.Fatalf("second batch was not consistent: %v", batches)
|
||||
}
|
||||
if batches[0] == batches[3] {
|
||||
t.Fatalf("two-card batch selection did not alternate: %v", batches)
|
||||
}
|
||||
// A forced rotation (declined retry) must also alternate the card.
|
||||
_, first, err := assignPaymentRoute(v, "82", true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
_, second, err := assignPaymentRoute(v, "83", true)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if cardFingerprint(first) == cardFingerprint(second) {
|
||||
t.Fatal("consecutive forced rotations reused the same card")
|
||||
}
|
||||
}
|
||||
@@ -21,6 +21,7 @@ type paymentRoute struct {
|
||||
Recipient string `json:"recipient"`
|
||||
NodeID string `json:"node_id"`
|
||||
Outbound json.RawMessage `json:"outbound"`
|
||||
Card string `json:"card,omitempty"`
|
||||
SelectedAt int64 `json:"selected_at"`
|
||||
}
|
||||
|
||||
@@ -75,6 +76,9 @@ func readPaymentRoute(v *vault.Vault, recipient string) (*paymentRoute, error) {
|
||||
if json.Unmarshal(raw, &route) != nil || route.Recipient != recipient || route.SelectedAt <= 0 || len(route.Outbound) == 0 || route.NodeID != outboundID(route.Outbound) {
|
||||
return nil, errors.New("saved payment route is invalid; refusing to select another node")
|
||||
}
|
||||
if route.Card != "" && !regexp.MustCompile(`^[0-9a-f]{64}$`).MatchString(route.Card) {
|
||||
return nil, errors.New("saved payment route card binding is invalid")
|
||||
}
|
||||
if _, err = proxy.ParseOutboundPool(append(append([]byte{'['}, route.Outbound...), ']')); err != nil {
|
||||
return nil, errors.New("saved payment outbound is invalid")
|
||||
}
|
||||
@@ -229,7 +233,7 @@ func rotateCoolingRouteLocked(v *vault.Vault, old *paymentRoute) (*paymentRoute,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
next := &paymentRoute{Recipient: old.Recipient, NodeID: outboundID(node), Outbound: node, SelectedAt: time.Now().Unix()}
|
||||
next := &paymentRoute{Recipient: old.Recipient, NodeID: outboundID(node), Outbound: node, Card: old.Card, SelectedAt: time.Now().Unix()}
|
||||
b, err := json.Marshal(next)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -124,7 +124,7 @@ func TestStripePoolUsesPinnedProxyAndDoesNotFallback(t *testing.T) {
|
||||
v := controlFixture(t)
|
||||
v.Put("payment-outbounds", nodes)
|
||||
v.Put("stripe-key", []byte("pk_live_Test"))
|
||||
s, err := newStripe(context.Background(), v, "1234")
|
||||
s, err := newStripe(context.Background(), v, "1234", paymentRead)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -147,7 +147,7 @@ func TestStripePoolUsesPinnedProxyAndDoesNotFallback(t *testing.T) {
|
||||
pinned, _ := v.Get("stripe-route:1234")
|
||||
upstream.Close()
|
||||
v.Put("payment-outbounds", []byte(`[]`))
|
||||
s, err = newStripe(context.Background(), v, "1234")
|
||||
s, err = newStripe(context.Background(), v, "1234", paymentRead)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ func Reconcile(ctx context.Context, v *vault.Vault, recipient string, port int)
|
||||
if err = verifySubmission(v, &r, plan); err != nil {
|
||||
return &r, err
|
||||
}
|
||||
s, err := newStripe(ctx, v, r.RecipientID)
|
||||
s, err := newStripe(ctx, v, r.RecipientID, paymentRead)
|
||||
if err != nil {
|
||||
return &r, err
|
||||
}
|
||||
|
||||
@@ -59,7 +59,7 @@ func PrepareRecoveryLinkForRecipient(ctx context.Context, v *vault.Vault, user,
|
||||
if !sessionURL(r.URL, r.SessionID) {
|
||||
return &r, errors.New("untrusted original checkout")
|
||||
}
|
||||
s, err := newStripe(ctx, v, r.RecipientID)
|
||||
s, err := newStripe(ctx, v, r.RecipientID, paymentRead)
|
||||
if err != nil {
|
||||
return &r, err
|
||||
}
|
||||
|
||||
+51
-48
@@ -25,8 +25,21 @@ type stripeClient struct {
|
||||
vault *vault.Vault
|
||||
closeRoute func()
|
||||
route *paymentRoute
|
||||
card card
|
||||
hasCard bool
|
||||
openRoute func(context.Context, json.RawMessage) (*http.Client, func(), error)
|
||||
}
|
||||
|
||||
// paymentMode separates read-only Stripe traffic from payment submissions so a
|
||||
// card+node pair is consumed exactly when a card is about to be tokenized.
|
||||
type paymentMode int
|
||||
|
||||
const (
|
||||
paymentRead paymentMode = iota
|
||||
paymentPay
|
||||
paymentRetry
|
||||
)
|
||||
|
||||
type stripeError struct {
|
||||
Code, Type string
|
||||
Message, Param, RequestID string
|
||||
@@ -59,7 +72,7 @@ type stripeAPIError struct {
|
||||
Intent *stripeIntentEvidence `json:"payment_intent"`
|
||||
}
|
||||
|
||||
func newStripe(ctx context.Context, v *vault.Vault, recipient string) (*stripeClient, error) {
|
||||
func newStripe(ctx context.Context, v *vault.Vault, recipient string, mode paymentMode) (*stripeClient, error) {
|
||||
key, e := v.Get("stripe-key")
|
||||
if e != nil {
|
||||
return nil, e
|
||||
@@ -68,9 +81,21 @@ func newStripe(ctx context.Context, v *vault.Vault, recipient string) (*stripeCl
|
||||
if !regexp.MustCompile(`^pk_live_[A-Za-z0-9]+$`).Match(key) {
|
||||
return nil, errors.New("invalid Stripe merchant publishable key")
|
||||
}
|
||||
route, e := selectPaymentRoute(v, recipient)
|
||||
if e != nil {
|
||||
return nil, e
|
||||
var route *paymentRoute
|
||||
var bound card
|
||||
switch mode {
|
||||
case paymentPay:
|
||||
if route, bound, e = assignPaymentRoute(v, recipient, false); e != nil {
|
||||
return nil, e
|
||||
}
|
||||
case paymentRetry:
|
||||
if route, bound, e = assignPaymentRoute(v, recipient, true); e != nil {
|
||||
return nil, e
|
||||
}
|
||||
default:
|
||||
if route, e = selectPaymentRoute(v, recipient); e != nil {
|
||||
return nil, e
|
||||
}
|
||||
}
|
||||
// Missing/empty pool is direct; an assigned order never silently falls back.
|
||||
client := &http.Client{Transport: &http.Transport{Proxy: nil, TLSHandshakeTimeout: 15 * time.Second}, Timeout: 35 * time.Second}
|
||||
@@ -83,7 +108,20 @@ func newStripe(ctx context.Context, v *vault.Vault, recipient string) (*stripeCl
|
||||
}
|
||||
}
|
||||
client.CheckRedirect = func(*http.Request, []*http.Request) error { return errStripeRedirect }
|
||||
return &stripeClient{http: client, key: string(key), vault: v, closeRoute: closeRoute, route: route, openRoute: proxy.OpenOutbound}, nil
|
||||
s := &stripeClient{http: client, key: string(key), vault: v, closeRoute: closeRoute, route: route, openRoute: proxy.OpenOutbound}
|
||||
if mode != paymentRead {
|
||||
s.card, s.hasCard = bound, true
|
||||
}
|
||||
return s, nil
|
||||
}
|
||||
|
||||
// paymentCard returns the card bound to this payment attempt. Legacy callers
|
||||
// and fixtures fall back to the first configured card.
|
||||
func (s *stripeClient) paymentCard() (card, error) {
|
||||
if s.hasCard {
|
||||
return s.card, nil
|
||||
}
|
||||
return readCard(s.vault)
|
||||
}
|
||||
func (s *stripeClient) close() {
|
||||
if s.closeRoute != nil {
|
||||
@@ -354,50 +392,15 @@ type card struct {
|
||||
State string `json:"billing_state"`
|
||||
}
|
||||
|
||||
func readCard(v *vault.Vault) (card, error) {
|
||||
raw, e := v.Get("card")
|
||||
if e != nil {
|
||||
return card{}, e
|
||||
}
|
||||
defer clear(raw)
|
||||
var c card
|
||||
if json.Unmarshal(raw, &c) != nil {
|
||||
return c, errors.New("invalid card record")
|
||||
}
|
||||
if !regexp.MustCompile(`^[0-9]{12,19}$`).MatchString(c.Number) || !regexp.MustCompile(`^(0[1-9]|1[0-2])$`).MatchString(c.Month) || !regexp.MustCompile(`^[0-9]{4}$`).MatchString(c.Year) || !regexp.MustCompile(`^[0-9]{3,4}$`).MatchString(c.CVC) || strings.TrimSpace(c.Name) == "" || !strings.Contains(c.Email, "@") {
|
||||
return c, errors.New("card, cardholder name or email is incomplete")
|
||||
}
|
||||
sum := 0
|
||||
for i, n := range c.Number {
|
||||
d := int(n - '0')
|
||||
if (len(c.Number)-i)%2 == 0 {
|
||||
d *= 2
|
||||
if d > 9 {
|
||||
d -= 9
|
||||
}
|
||||
}
|
||||
sum += d
|
||||
}
|
||||
if sum%10 != 0 {
|
||||
return c, errors.New("card number checksum is invalid")
|
||||
}
|
||||
year, _ := strconv.Atoi(c.Year)
|
||||
month, _ := strconv.Atoi(c.Month)
|
||||
if !time.Now().Before(time.Date(year, time.Month(month)+1, 1, 0, 0, 0, 0, time.UTC)) {
|
||||
return c, errors.New("card has expired")
|
||||
}
|
||||
if c.Country == "" {
|
||||
return c, errors.New("Stripe requires a billing address; supply the card billing country and applicable address fields")
|
||||
}
|
||||
if !regexp.MustCompile(`^[A-Z]{2}$`).MatchString(c.Country) {
|
||||
return c, errors.New("invalid supplied billing country")
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
func CheckPaymentConfiguration(v *vault.Vault) error {
|
||||
_, err := readCard(v)
|
||||
return err
|
||||
cards, err := readCards(v)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if len(usableCards(cards)) == 0 {
|
||||
return ErrNoUsableCard
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (s *stripeClient) tokenize(ctx context.Context, r *Record, c card) (string, error) {
|
||||
form := url.Values{"type": {"card"}, "card[number]": {c.Number}, "card[exp_month]": {c.Month}, "card[exp_year]": {c.Year}, "card[cvc]": {c.CVC}, "billing_details[name]": {c.Name}, "billing_details[email]": {c.Email}}
|
||||
|
||||
@@ -34,7 +34,7 @@ func TestStripeDirectAndXProxyStaySeparate(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
s, err := newStripe(context.Background(), v, "1234")
|
||||
s, err := newStripe(context.Background(), v, "1234", paymentRead)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
/>
|
||||
<title>XGift · 兑换码管理</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<script type="module" src="/admin.js?v=b962140d448c"></script>
|
||||
<script type="module" src="/admin.js?v=00ddc63a3139"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
var _A=Object.create;var Kx=Object.defineProperty;var zA=Object.getOwnPropertyDescriptor;var jA=Object.getOwnPropertyNames;var BA=Object.getPrototypeOf,UA=Object.prototype.hasOwnProperty;var Vo=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(o){throw t=0,o}};var LA=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of jA(t))!UA.call(e,n)&&n!==o&&Kx(e,n,{get:()=>t[n],enumerable:!(r=zA(t,n))||r.enumerable});return e};var C=(e,t,o)=>(o=e!=null?_A(BA(e)):{},LA(t||!e||!e.__esModule?Kx(o,"default",{value:e,enumerable:!0}):o,e));var s1=Vo(we=>{"use strict";var bg=Symbol.for("react.transitional.element"),IA=Symbol.for("react.portal"),HA=Symbol.for("react.fragment"),$A=Symbol.for("react.strict_mode"),VA=Symbol.for("react.profiler"),FA=Symbol.for("react.consumer"),qA=Symbol.for("react.context"),GA=Symbol.for("react.forward_ref"),YA=Symbol.for("react.suspense"),KA=Symbol.for("react.memo"),Jx=Symbol.for("react.lazy"),WA=Symbol.for("react.activity"),XA=Symbol.for("react.view_transition"),Wx=Symbol.iterator;function QA(e){return e===null||typeof e!="object"?null:(e=Wx&&e[Wx]||e["@@iterator"],typeof e=="function"?e:null)}var e1={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},t1=Object.assign,o1={};function pl(e,t,o){this.props=e,this.context=t,this.refs=o1,this.updater=o||e1}pl.prototype.isReactComponent={};pl.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};pl.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function r1(){}r1.prototype=pl.prototype;function vg(e,t,o){this.props=e,this.context=t,this.refs=o1,this.updater=o||e1}var xg=vg.prototype=new r1;xg.constructor=vg;t1(xg,pl.prototype);xg.isPureReactComponent=!0;var Xx=Array.isArray;function Tg(){}var yt={H:null,A:null,T:null,S:null},n1=Object.prototype.hasOwnProperty;function Pg(e,t,o){var r=o.ref;return{$$typeof:bg,type:e,key:t,ref:r!==void 0?r:null,props:o}}function ZA(e,t){return Pg(e.type,t,e.props)}function Sg(e){return typeof e=="object"&&e!==null&&e.$$typeof===bg}function JA(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(o){return t[o]})}var Qx=/\/+/g;function gg(e,t){return typeof e=="object"&&e!==null&&e.key!=null?JA(""+e.key):t.toString(36)}function e3(e){switch(e.status){case"fulfilled":return e.value;case"rejected":throw e.reason;default:switch(typeof e.status=="string"?e.then(Tg,Tg):(e.status="pending",e.then(function(t){e.status==="pending"&&(e.status="fulfilled",e.value=t)},function(t){e.status==="pending"&&(e.status="rejected",e.reason=t)})),e.status){case"fulfilled":return e.value;case"rejected":throw e.reason}}throw e}function ll(e,t,o,r,n){var a=typeof e;(a==="undefined"||a==="boolean")&&(e=null);var i=!1;if(e===null)i=!0;else switch(a){case"bigint":case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case bg:case IA:i=!0;break;case Jx:return i=e._init,ll(i(e._payload),t,o,r,n)}}if(i)return n=n(e),i=r===""?"."+gg(e,0):r,Xx(n)?(o="",i!=null&&(o=i.replace(Qx,"$&/")+"/"),ll(n,t,o,"",function(p){return p})):n!=null&&(Sg(n)&&(n=ZA(n,o+(n.key==null||e&&e.key===n.key?"":(""+n.key).replace(Qx,"$&/")+"/")+i)),t.push(n)),1;i=0;var s=r===""?".":r+":";if(Xx(e))for(var l=0;l<e.length;l++)r=e[l],a=s+gg(r,l),i+=ll(r,t,o,a,n);else if(l=QA(e),typeof l=="function")for(e=l.call(e),l=0;!(r=e.next()).done;)r=r.value,a=s+gg(r,l++),i+=ll(r,t,o,a,n);else if(a==="object"){if(typeof e.then=="function")return ll(e3(e),t,o,r,n);throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.")}return i}function Jf(e,t,o){if(e==null)return e;var r=[],n=0;return ll(e,r,"","",function(a){return t.call(o,a,n++)}),r}function t3(e){if(e._status===-1){var t=e._result,o=t();o.then(function(r){(e._status===0||e._status===-1)&&(e._status=1,e._result=r,o.status===void 0&&(o.status="fulfilled",o.value=r))},function(r){(e._status===0||e._status===-1)&&(e._status=2,e._result=r,o.status===void 0&&(o.status="rejected",o.reason=r))}),e._status===-1&&(e._status=0,e._result=o)}if(e._status===1)return e._result.default;throw e._result}var Zx=typeof reportError=="function"?reportError:function(e){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof e=="object"&&e!==null&&typeof e.message=="string"?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",e);return}console.error(e)};function a1(e){var t=yt.T,o={};o.types=t!==null?t.types:nullLine truncated
|
||||
var V3=Object.create;var t1=Object.defineProperty;var F3=Object.getOwnPropertyDescriptor;var q3=Object.getOwnPropertyNames;var G3=Object.getPrototypeOf,Y3=Object.prototype.hasOwnProperty;var Yo=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(o){throw t=0,o}};var W3=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of q3(t))!Y3.call(e,n)&&n!==o&&t1(e,n,{get:()=>t[n],enumerable:!(r=F3(t,n))||r.enumerable});return e};var C=(e,t,o)=>(o=e!=null?V3(G3(e)):{},W3(t||!e||!e.__esModule?t1(o,"default",{value:e,enumerable:!0}):o,e));var m1=Yo(Ne=>{"use strict";var Rg=Symbol.for("react.transitional.element"),K3=Symbol.for("react.portal"),X3=Symbol.for("react.fragment"),Q3=Symbol.for("react.strict_mode"),Z3=Symbol.for("react.profiler"),J3=Symbol.for("react.consumer"),eA=Symbol.for("react.context"),tA=Symbol.for("react.forward_ref"),oA=Symbol.for("react.suspense"),rA=Symbol.for("react.memo"),i1=Symbol.for("react.lazy"),nA=Symbol.for("react.activity"),aA=Symbol.for("react.view_transition"),o1=Symbol.iterator;function iA(e){return e===null||typeof e!="object"?null:(e=o1&&e[o1]||e["@@iterator"],typeof e=="function"?e:null)}var s1={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},l1=Object.assign,p1={};function gl(e,t,o){this.props=e,this.context=t,this.refs=p1,this.updater=o||s1}gl.prototype.isReactComponent={};gl.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};gl.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function c1(){}c1.prototype=gl.prototype;function Og(e,t,o){this.props=e,this.context=t,this.refs=p1,this.updater=o||s1}var wg=Og.prototype=new c1;wg.constructor=Og;l1(wg,gl.prototype);wg.isPureReactComponent=!0;var r1=Array.isArray;function Eg(){}var bt={H:null,A:null,T:null,S:null},u1=Object.prototype.hasOwnProperty;function Ng(e,t,o){var r=o.ref;return{$$typeof:Rg,type:e,key:t,ref:r!==void 0?r:null,props:o}}function sA(e,t){return Ng(e.type,t,e.props)}function Mg(e){return typeof e=="object"&&e!==null&&e.$$typeof===Rg}function lA(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(o){return t[o]})}var n1=/\/+/g;function Cg(e,t){return typeof e=="object"&&e!==null&&e.key!=null?lA(""+e.key):t.toString(36)}function pA(e){switch(e.status){case"fulfilled":return e.value;case"rejected":throw e.reason;default:switch(typeof e.status=="string"?e.then(Eg,Eg):(e.status="pending",e.then(function(t){e.status==="pending"&&(e.status="fulfilled",e.value=t)},function(t){e.status==="pending"&&(e.status="rejected",e.reason=t)})),e.status){case"fulfilled":return e.value;case"rejected":throw e.reason}}throw e}function hl(e,t,o,r,n){var a=typeof e;(a==="undefined"||a==="boolean")&&(e=null);var i=!1;if(e===null)i=!0;else switch(a){case"bigint":case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case Rg:case K3:i=!0;break;case i1:return i=e._init,hl(i(e._payload),t,o,r,n)}}if(i)return n=n(e),i=r===""?"."+Cg(e,0):r,r1(n)?(o="",i!=null&&(o=i.replace(n1,"$&/")+"/"),hl(n,t,o,"",function(p){return p})):n!=null&&(Mg(n)&&(n=sA(n,o+(n.key==null||e&&e.key===n.key?"":(""+n.key).replace(n1,"$&/")+"/")+i)),t.push(n)),1;i=0;var s=r===""?".":r+":";if(r1(e))for(var l=0;l<e.length;l++)r=e[l],a=s+Cg(r,l),i+=hl(r,t,o,a,n);else if(l=iA(e),typeof l=="function")for(e=l.call(e),l=0;!(r=e.next()).done;)r=r.value,a=s+Cg(r,l++),i+=hl(r,t,o,a,n);else if(a==="object"){if(typeof e.then=="function")return hl(pA(e),t,o,r,n);throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.")}return i}function sd(e,t,o){if(e==null)return e;var r=[],n=0;return hl(e,r,"","",function(a){return t.call(o,a,n++)}),r}function cA(e){if(e._status===-1){var t=e._result,o=t();o.then(function(r){(e._status===0||e._status===-1)&&(e._status=1,e._result=r,o.status===void 0&&(o.status="fulfilled",o.value=r))},function(r){(e._status===0||e._status===-1)&&(e._status=2,e._result=r,o.status===void 0&&(o.status="rejected",o.reason=r))}),e._status===-1&&(e._status=0,e._result=o)}if(e._status===1)return e._result.default;throw e._result}var a1=typeof reportError=="function"?reportError:function(e){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof e=="object"&&e!==null&&typeof e.message=="string"?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",e);return}console.error(e)};function f1(e){var t=bt.T,o={};o.types=t!==null?t.types:nullLine truncated
|
||||
at`)?" (<anonymous>)":-1<o.stack.indexOf("@")?"@unknown:0:0":""}return`
|
||||
`+Zb+e+Z2}var Jb=!1;function ev(e,t){if(!e||Jb)return"";Jb=!0;var o=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var r={DetermineComponentFrameRoot:function(){try{if(t){var m=function(){throw Error()};if(Object.defineProperty(m.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(m,[])}catch(g){var f=g}Reflect.construct(e,[],m)}else{try{m.call()}catch(g){f=g}m=!1;try{var u=Object.getOwnPropertyDescriptor(e.prototype,"props");Object.defineProperty(e.prototype,"props",{configurable:!0,set:function(){throw Error()}}),m=!0,new e}finally{m&&(u!==void 0?Object.defineProperty(e.prototype,"props",u):delete e.prototype.props)}}}else{try{throw Error()}catch(g){f=g}(m=e())&&typeof m.catch=="function"&&m.catch(function(){})}}catch(g){if(g&&f&&typeof g.stack=="string")return[g.stack,f.stack]}return[null,null]}};r.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var n=Object.getOwnPropertyDescriptor(r.DetermineComponentFrameRoot,"name");n&&n.configurable&&Object.defineProperty(r.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var a=r.DetermineComponentFrameRoot(),i=a[0],s=a[1];if(i&&s){var l=i.split(`
|
||||
`+av+e+aO}var iv=!1;function sv(e,t){if(!e||iv)return"";iv=!0;var o=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var r={DetermineComponentFrameRoot:function(){try{if(t){var d=function(){throw Error()};if(Object.defineProperty(d.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(d,[])}catch(g){var f=g}Reflect.construct(e,[],d)}else{try{d.call()}catch(g){f=g}d=!1;try{var u=Object.getOwnPropertyDescriptor(e.prototype,"props");Object.defineProperty(e.prototype,"props",{configurable:!0,set:function(){throw Error()}}),d=!0,new e}finally{d&&(u!==void 0?Object.defineProperty(e.prototype,"props",u):delete e.prototype.props)}}}else{try{throw Error()}catch(g){f=g}(d=e())&&typeof d.catch=="function"&&d.catch(function(){})}}catch(g){if(g&&f&&typeof g.stack=="string")return[g.stack,f.stack]}return[null,null]}};r.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var n=Object.getOwnPropertyDescriptor(r.DetermineComponentFrameRoot,"name");n&&n.configurable&&Object.defineProperty(r.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var a=r.DetermineComponentFrameRoot(),i=a[0],s=a[1];if(i&&s){var l=i.split(`
|
||||
`),p=s.split(`
|
||||
`);for(n=r=0;r<l.length&&!l[r].includes("DetermineComponentFrameRoot");)r++;for(;n<p.length&&!p[n].includes("DetermineComponentFrameRoot");)n++;if(r===l.length||n===p.length)for(r=l.length-1,n=p.length-1;1<=r&&0<=n&&l[r]!==p[n];)n--;for(;1<=r&&0<=n;r--,n--)if(l[r]!==p[n]){if(r!==1||n!==1)do if(r--,n--,0>n||l[r]!==p[n]){var c=`
|
||||
`+l[r].replace(" at new "," at ");return e.displayName&&c.includes("<anonymous>")&&(c=c.replace("<anonymous>",e.displayName)),c}while(1<=r&&0<=n);break}}}finally{Jb=!1,Error.prepareStackTrace=o}return(o=e?e.displayName||e.name:"")?xi(o):""}function gU(e,t){switch(e.tag){case 26:case 27:case 5:return xi(e.type);case 16:return xi("Lazy");case 13:return e.child!==t&&t!==null?xi("Suspense Fallback"):xi("Suspense");case 19:return xi("SuspenseList");case 0:case 15:return ev(e.type,!1);case 11:return ev(e.type.render,!1);case 1:return ev(e.type,!0);case 31:return xi("Activity");case 30:return xi("ViewTransition");default:return""}}function J2(e){try{var t="",o=null;do t+=gU(e,o),o=e,e=e.return;while(e);return t}catch(r){return`
|
||||
`+l[r].replace(" at new "," at ");return e.displayName&&c.includes("<anonymous>")&&(c=c.replace("<anonymous>",e.displayName)),c}while(1<=r&&0<=n);break}}}finally{iv=!1,Error.prepareStackTrace=o}return(o=e?e.displayName||e.name:"")?Oi(o):""}function RU(e,t){switch(e.tag){case 26:case 27:case 5:return Oi(e.type);case 16:return Oi("Lazy");case 13:return e.child!==t&&t!==null?Oi("Suspense Fallback"):Oi("Suspense");case 19:return Oi("SuspenseList");case 0:case 15:return sv(e.type,!1);case 11:return sv(e.type.render,!1);case 1:return sv(e.type,!0);case 31:return Oi("Activity");case 30:return Oi("ViewTransition");default:return""}}function iO(e){try{var t="",o=null;do t+=RU(e,o),o=e,e=e.return;while(e);return t}catch(r){return`
|
||||
Error generating stack: `+r.message+`
|
||||
`+r.stack}}var Lv=Object.prototype.hasOwnProperty,$0=no.unstable_scheduleCallback,tv=no.unstable_cancelCallback,TU=no.unstable_shouldYield,bU=no.unstable_requestPaint,jr=no.unstable_now,vU=no.unstable_getCurrentPriorityLevel,Hw=no.unstable_ImmediatePriority,$w=no.unstable_UserBlockingPriority,vh=no.unstable_NormalPriority,xU=no.unstable_LowPriority,Vw=no.unstable_IdlePriority,PU=no.log,SU=no.unstable_setDisableYieldValue,If=null,Br=null;function Ri(e){if(typeof PU=="function"&&SU(e),Br&&typeof Br.setStrictMode=="function")try{Br.setStrictMode(If,e)}catch{}}var Ur=Math.clz32?Math.clz32:RU,CU=Math.log,EU=Math.LN2;function RU(e){return e>>>=0,e===0?32:31-(CU(e)/EU|0)|0}var Dy=256,ky=262144,_y=4194304;function Ls(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&-e;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Gh(e,t,o){var r=e.pendingLanes;if(r===0)return 0;var n=0,a=e.suspendedLanes,i=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s!==0?(r=s&~a,r!==0?n=Ls(r):(i&=s,i!==0?n=Ls(i):o||(o=s&~e,o!==0&&(n=Ls(o))))):(s=r&~a,s!==0?n=Ls(s):i!==0?n=Ls(i):o||(o=r&~e,o!==0&&(n=Ls(o)))),n===0?0:t!==0&&t!==n&&(t&a)===0&&(a=n&-n,o=t&-t,a>=o||a===32&&(o&4194048)!==0)?t:n}function Hf(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Fw(e,t){(t&8)!==0&&(t|=t&32);var o=e.entangledLanes;if(o!==0)for(e=e.entanglements,o&=t;0<o;){var r=31-Ur(o),n=1<<r;t|=e[r],o&=~n}return t}function OU(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function qw(){var e=_y;return _y<<=1,(_y&62914560)===0&&(_y=4194304),e}function ov(e){for(var t=[],o=0;31>o;o++)t.push(e);return t}function $f(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function wU(e,t,o,r,n,a){var i=e.pendingLanes;e.pendingLanes=o,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=o,e.entangledLanes&=o,e.errorRecoveryDisabledLanes&=o,e.shellSuspendCounter=0;var s=e.entanglements,l=e.expirationTimes,p=e.hiddenUpdates;for(o=i&~o;0<o;){var c=31-Ur(o),m=1<<c;s[c]=0,l[c]=-1;var f=p[c];if(f!==null)for(p[c]=null,c=0;c<f.length;c++){var u=f[c];u!==null&&(u.lane&=-536870913)}o&=~m}r!==0&&Gw(e,r,0),a!==0&&n===0&&e.tag!==0&&(e.suspendedLanes|=a&~(i&~t))}function Gw(e,t,o){e.pendingLanes|=t,e.suspendedLanes&=~t;var r=31-Ur(t);e.entangledLanes|=t,e.entanglements[r]=e.entanglements[r]|1073741824|o&261930}function Yw(e,t){var o=e.entangledLanes|=t;for(e=e.entanglements;o;){var r=31-Ur(o),n=1<<r;n&t|e[r]&t&&(e[r]|=t),o&=~n}}function Kw(e,t){var o=t&-t;return o=(o&42)!==0?1:V0(o),(o&(e.suspendedLanes|t))!==0?0:o}function V0(e){switch(e){case 2:e=1;break;case 8:e=4;break;case 32:e=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:e=128;break;case 268435456:e=134217728;break;default:e=0}return e}function F0(e){return e&=-e,2<e?8<e?(e&134217727)!==0?32:268435456:8:2}function Ww(){var e=Je.p;return e!==0?e:(e=window.event,e===void 0?32:MM(e.type))}function eO(e,t){var o=Je.p;try{return Je.p=e,t()}finally{Je.p=o}}var Wa=Math.random().toString(36).slice(2),Oo="__reactFiber$"+Wa,gr="__reactProps$"+Wa,yc="__reactContainer$"+Wa,tO="__reactEvents$"+Wa,NU="__reactListeners$"+Wa,MU="__reactHandles$"+Wa,oO="__reactResources$"+Wa,Vf="__reactMarker$"+Wa,xh="__reactLoad$"+Wa;function Yh(e){delete e[Oo],delete e[gr],delete e[NU],delete e[MU]}function $s(e){var t;if(t=e[Oo])return t;for(var o=e.parentNode;o;){if(t=o[yc]||o[Oo]){if(o=t.alternate,t.child!==null||o!==null&&o.child!==null)for(e=bw(e);e!==null;){if(o=e[Oo])return o;e=bw(e)}return t}e=o,o=e.parentNode}return null}function hc(e){if(e=e[Oo]||e[yc]){var t=e.tag;if(t===5||t===6||t===13||t===31||t===26||t===27||t===3)return e}return null}function sf(e){var t=e.tag;if(t===5||t===26||t===27||t===6)return e.stateNode;throw Error(V(33))}function Gp(e){var t=e[oO];return t||(t=e[oO]={hoistableStyles:new Map,hoistableScripts:new Map}),t}function yo(e){e[Vf]=!0}function Xw(e){e[xh]=void 0}var Qw=new Set,Zw={};function nl(e,t){rc(e,t),rc(e+"Capt
Line truncated
|
||||
`).replace(y8,"")}function sM(e,t){return t=pw(t),pw(e)===t}function it(e,t,o,r,n,a){switch(o){case"children":if(typeof r=="string")t==="body"||t==="textarea"&&r===""||nc(e,r);else if(typeof r=="number"||typeof r=="bigint")t!=="body"&&nc(e,""+r);else return;break;case"className":zy(e,"class",r);break;case"tabIndex":zy(e,"tabindex",r);break;case"dir":case"role":case"viewBox":case"width":case"height":zy(e,o,r);break;case"style":nN(e,r,a);return;case"data":if(t!=="object"){zy(e,"data",r);break}case"src":case"href":if(r===""&&(t!=="a"||o!=="href")){e.removeAttribute(o);break}if(r==null||typeof r=="function"||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=Jy(r),e.setAttribute(o,r);break;case"action":case"formAction":if(typeof r=="function"){e.setAttribute(o,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof a=="function"&&(o==="formAction"?(t!=="input"&&it(e,t,"name",n.name,n,null),it(e,t,"formEncType",n.formEncType,n,null),it(e,t,"formMethod",n.formMethod,n,null),it(e,t,"formTarget",n.formTarget,n,null)):(it(e,t,"encType",n.encType,n,null),it(e,t,"method",n.method,n,null),it(e,t,"target",n.target,n,null)));if(r==null||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=Jy(r),e.setAttribute(o,r);break;case"onClick":r!=null&&(e.onclick=ra);return;case"onScroll":r!=null&&Ie("scroll",e);return;case"onScrollEnd":r!=null&&Ie("scrollend",e);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(V(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(V(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"multiple":e.multiple=r&&typeof r!="function"&&typeof r!="symbol";break;case"muted":e.muted=r&&typeof r!="function"&&typeof r!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(r==null||typeof r=="function"||typeof r=="boolean"||typeof r=="symbol"){e.removeAttribute("xlink:href");break}o=Jy(r),e.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",o);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"credentialless":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":r&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,""):e.removeAttribute(o);break;case"capture":case"download":r===!0?e.setAttribute(o,""):r!==!1&&r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"cols":case"rows":case"size":case"span":r!=null&&typeof r!="function"&&typeof r!="symbol"&&!isNaN(r)&&1<=r?e.setAttribute(o,r):e.removeAttribute(o);break;case"rowSpan":case"start":r==null||typeof r=="function"||typeof r=="symbol"||isNaN(r)?e.removeAttribute(o):e.setAttribute(o,r);break;case"popover":Ie("beforetoggle",e),Ie("toggle",e),Zy(e,"popover",r);break;case"xlinkActuate":Ba(e,"http://www.w3.org/1999/xlink","xlink:actuate",r);break;case"xlinkArcrole":Ba(e,"http://www.w3.org/1999/xlink","xlink:arcrole",r);break;case"xlinkRole":Ba(e,"http://www.w3.org/1999/xlink","xlink:role",r);break;case"xlinkShow":Ba(e,"http://www.w3.org/1999/xlink","xlink:show",r);break;case"xlinkTitle":Ba(e,"http://www.w3.org/1999/xlink","xlink:title",r);break;case"xlinkType":Ba(e,"http://www.w3.org/1999/xlink","xlink:type",r);break;case"xmlBase":Ba(e,"http://www.w3.org/XML/1998/namespace","xml:base",r);break;case"xmlLang":Ba(e,"http://www.w3.org/XML/1998/namespace","xml:lang",r);break;case"xmlSpace":Ba(e,"http://www.w3.org/XML/1998/namespace","xml:space",r);break;case"is":Zy(e,"is",r);break;case"innerText":case"textContent":return;default:if(!(2<o.length)||o[0]!=="o"&&o[0]!=="O"||o[1]!=="n"&&o[1]!=="N")o=jU.get(o)||o,Zy(e,o,r);else return}Qe=!0}function N0(e,t,o,r,n,a){switch(o){case"style":nN(e,r,a);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(V(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(V(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"children":if(typeof r=="string")nc(e,r);else if(typeof r=="number"||typeof r=="bigint")nc(e,""+r);else return;break;case"onScroll":r!=null&&Ie("scroll",e);return;case"onScrollEnd":r!=null&&Ie("scrollend",e);return;case"onClick":r
Line truncated
|
||||
`)),(MP!==void 0?dD:uD)(m,s,l,p,c)}}var xF=Xg();function mD(e,t=Number.MIN_SAFE_INTEGER,o=Number.MAX_SAFE_INTEGER){return Math.max(t,Math.min(e,o))}var Qg=mD;function Jg(e,t=0,o=1){return Qg(e,t,o)}function yD(e){e=e.slice(1);let t=new RegExp(`.{1,${e.length>=6?2:1}}`,"g"),o=e.match(t);return o&&o[0].length===1&&(o=o.map(r=>r+r)),o?`rgb${o.length===4?"a":""}(${o.map((r,n)=>n<3?parseInt(r,16):Math.round(parseInt(r,16)/255*1e3)/1e3).join(", ")})`:""}function oi(e){if(e.type)return e;if(e.charAt(0)==="#")return oi(yD(e));let t=e.indexOf("("),o=e.substring(0,t);if(!["rgb","rgba","hsl","hsla","color"].includes(o))throw new Error(io(9,e));let r=e.substring(t+1,e.length-1),n;if(o==="color"){if(r=r.split(" "),n=r.shift(),r.length===4&&r[3].charAt(0)==="/"&&(r[3]=r[3].slice(1)),!["srgb","display-p3","a98-rgb","prophoto-rgb","rec-2020"].includes(n))throw new Error(io(10,n))}else r=r.split(",");return r=r.map(a=>parseFloat(a)),{type:o,values:r,colorSpace:n}}var hD=e=>{let t=oi(e);return t.values.slice(0,3).map((o,r)=>t.type.includes("hsl")&&r!==0?`${o}%`:o).join(" ")},Al=(e,t)=>{try{return hD(e)}catch{return e}};function Hd(e){let{type:t,colorSpace:o}=e,{values:r}=e;return t.includes("rgb")?r=r.map((n,a)=>a<3?parseInt(n,10):n):t.includes("hsl")&&(r[1]=`${r[1]}%`,r[2]=`${r[2]}%`),t.includes("color")?r=`${o} ${r.join(" ")}`:r=`${r.join(", ")}`,`${t}(${r})`}function eT(e){e=oi(e);let{values:t}=e,o=t[0],r=t[1]/100,n=t[2]/100,a=r*Math.min(n,1-n),i=(p,c=(p+o/30)%12)=>n-a*Math.max(Math.min(c-3,9-c,1),-1),s="rgb",l=[Math.round(i(0)*255),Math.round(i(8)*255),Math.round(i(4)*255)];return e.type==="hsla"&&(s+="a",l.push(t[3])),Hd({type:s,values:l})}function Zg(e){e=oi(e);let t=e.type==="hsl"||e.type==="hsla"?oi(eT(e)).values:e.values;return t=t.map(o=>(e.type!=="color"&&(o/=255),o<=.03928?o/12.92:((o+.055)/1.055)**2.4)),Number((.2126*t[0]+.7152*t[1]+.0722*t[2]).toFixed(3))}function AP(e,t){let o=Zg(e),r=Zg(t);return(Math.max(o,r)+.05)/(Math.min(o,r)+.05)}function ri(e,t){return e=oi(e),t=Jg(t),(e.type==="rgb"||e.type==="hsl")&&(e.type+="a"),e.type==="color"?e.values[3]=`/${t}`:e.values[3]=t,Hd(e)}function ni(e,t,o){try{return ri(e,t)}catch{return e}}function Dl(e,t){if(e=oi(e),t=Jg(t),e.type.includes("hsl"))e.values[2]*=1-t;else if(e.type.includes("rgb")||e.type.includes("color"))for(let o=0;o<3;o+=1)e.values[o]*=1-t;return Hd(e)}function et(e,t,o){try{return Dl(e,t)}catch{return e}}function kl(e,t){if(e=oi(e),t=Jg(t),e.type.includes("hsl"))e.values[2]+=(100-e.values[2])*t;else if(e.type.includes("rgb"))for(let o=0;o<3;o+=1)e.values[o]+=(255-e.values[o])*t;else if(e.type.includes("color"))for(let o=0;o<3;o+=1)e.values[o]+=(1-e.values[o])*t;return Hd(e)}function tt(e,t,o){try{return kl(e,t)}catch{return e}}function $d(e,t=.15){return Zg(e)>.5?Dl(e,t):kl(e,t)}function Vc(e,t,o){try{return $d(e,t)}catch{return e}}var GP=C(I(),1);var _P=C(I(),1);var DP=C(I(),1),gD=DP.createContext(null),Vd=gD;var tT=C(I(),1);function ga(){return tT.useContext(Vd)}var TD=typeof Symbol=="function"&&Symbol.for,kP=TD?Symbol.for("mui.nested"):"__THEME_NESTED__";var zP=C(U(),1);function bD(e,t){return typeof t=="function"?t(e):{...e,...t}}function vD(e){let{children:t,theme:o}=e,r=ga(),n=_P.useMemo(()=>{let a=r===null?{...o}:bD(r,o);return a!=null&&(a[kP]=r!==null),a},[o,r]);return(0,zP.jsx)(Vd.Provider,{value:n,children:t})}var Fd=vD;var qd=C(I(),1);var jP=C(U(),1),BP=qd.createContext();function xD({value:e,...t}){return(0,jP.jsx)(BP.Provider,{value:e??!0,...t})}var ai=()=>qd.useContext(BP)??!1,UP=xD;var Gd=C(I(),1);var LP=C(U(),1),IP=Gd.createContext(void 0);function PD({value:e,children:t}){return(0,LP.jsx)(IP.Provider,{value:e,children:t})}function SD(e){let{theme:t,name:o,props:r}=e;if(!t||!t.components||!t.components[o])return r;let n=t.components[o];return n.defaultProps?qn(n.defaultProps,r,t.components.mergeClassNameAndStyle):!n.styleOverrides&&!n.variants?qn(n,r,t.components.mergeClassNameAndStyle):r}function oT({props:e,name:t}){let o=Gd.useContext(IP);return SD({props:e,name:t,theme:{components:o}})}var Yd=PD;var Fc=C(I(),1),HP=0;function CD(e){let[t,o]=Fc.useState(e),r=e||t;return Fc.useEffect(()=>{t==null&&(HP+=1,o(`mui-${HP}`))},[t]),r}var ED={...Fc},$P=ED.useId;function Yr(e){if($P!==void 0){let t=$P();return e??t}return CD(e)}var VP=C(U(),1);function rT(e){let t=ya(),o=Yr()||"",{modularCssLayers:r}=e,n="mui.global, mui.components, mui.theme, mui.custom, mui.sx";return!r||t!==null?n="":typeof r=="string"?n=r.replace(/mui(?!\.)/g,n):n=`@layer ${n};`,Gt(()=>{let a=document.querySelector("head");if(!a)return;let i=a.firstChild;if(n){if(i&&i.hasAttribute?.("data-mui-layer-order")&&i.getAttribute("data-mui-layer-order")===o)return;let s=document.createElement("style");s.setAttribute("data-mui-layer-order",o),s.textContent=n,a.prepend(s)}else a.querySelector(`style[data-mui-layer-order="${o}"]`)?.remove()},[n,o]),n?(0,VP.jsx)(Rl,{styles:n}):null}var _l=C(U(),1),FP={};function qP(e,t,o,r=!1){return GP.useMemo(()=>{let n=e&&t[e]||t;if(typeof o=="f
Line truncated
|
||||
${s}.classList.add('${f}'.replace('%s', colorScheme));`}let m=c.match(/\[([^[\]]+)\]/);if(m){let[f,u]=m[1].split("=");u||(p+=`${s}.removeAttribute('${f}'.replace('%s', light));
|
||||
`+r.stack}}var Gv=Object.prototype.hasOwnProperty,K0=co.unstable_scheduleCallback,lv=co.unstable_cancelCallback,OU=co.unstable_shouldYield,wU=co.unstable_requestPaint,jr=co.unstable_now,NU=co.unstable_getCurrentPriorityLevel,Ww=co.unstable_ImmediatePriority,Kw=co.unstable_UserBlockingPriority,wh=co.unstable_NormalPriority,MU=co.unstable_LowPriority,Xw=co.unstable_IdlePriority,AU=co.log,kU=co.unstable_setDisableYieldValue,Yf=null,Br=null;function ki(e){if(typeof AU=="function"&&kU(e),Br&&typeof Br.setStrictMode=="function")try{Br.setStrictMode(Yf,e)}catch{}}var Ur=Math.clz32?Math.clz32:zU,DU=Math.log,_U=Math.LN2;function zU(e){return e>>>=0,e===0?32:31-(DU(e)/_U|0)|0}var Iy=256,$y=262144,Hy=4194304;function Gs(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&-e;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function eg(e,t,o){var r=e.pendingLanes;if(r===0)return 0;var n=0,a=e.suspendedLanes,i=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s!==0?(r=s&~a,r!==0?n=Gs(r):(i&=s,i!==0?n=Gs(i):o||(o=s&~e,o!==0&&(n=Gs(o))))):(s=r&~a,s!==0?n=Gs(s):i!==0?n=Gs(i):o||(o=r&~e,o!==0&&(n=Gs(o)))),n===0?0:t!==0&&t!==n&&(t&a)===0&&(a=n&-n,o=t&-t,a>=o||a===32&&(o&4194048)!==0)?t:n}function Wf(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function Qw(e,t){(t&8)!==0&&(t|=t&32);var o=e.entangledLanes;if(o!==0)for(e=e.entanglements,o&=t;0<o;){var r=31-Ur(o),n=1<<r;t|=e[r],o&=~n}return t}function jU(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function Zw(){var e=Hy;return Hy<<=1,(Hy&62914560)===0&&(Hy=4194304),e}function pv(e){for(var t=[],o=0;31>o;o++)t.push(e);return t}function Kf(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function BU(e,t,o,r,n,a){var i=e.pendingLanes;e.pendingLanes=o,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=o,e.entangledLanes&=o,e.errorRecoveryDisabledLanes&=o,e.shellSuspendCounter=0;var s=e.entanglements,l=e.expirationTimes,p=e.hiddenUpdates;for(o=i&~o;0<o;){var c=31-Ur(o),d=1<<c;s[c]=0,l[c]=-1;var f=p[c];if(f!==null)for(p[c]=null,c=0;c<f.length;c++){var u=f[c];u!==null&&(u.lane&=-536870913)}o&=~d}r!==0&&Jw(e,r,0),a!==0&&n===0&&e.tag!==0&&(e.suspendedLanes|=a&~(i&~t))}function Jw(e,t,o){e.pendingLanes|=t,e.suspendedLanes&=~t;var r=31-Ur(t);e.entangledLanes|=t,e.entanglements[r]=e.entanglements[r]|1073741824|o&261930}function e5(e,t){var o=e.entangledLanes|=t;for(e=e.entanglements;o;){var r=31-Ur(o),n=1<<r;n&t|e[r]&t&&(e[r]|=t),o&=~n}}function t5(e,t){var o=t&-t;return o=(o&42)!==0?1:X0(o),(o&(e.suspendedLanes|t))!==0?0:o}function X0(e){switch(e){case 2:e=1;break;case 8:e=4;break;case 32:e=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:e=128;break;case 268435456:e=134217728;break;default:e=0}return e}function Q0(e){return e&=-e,2<e?8<e?(e&134217727)!==0?32:268435456:8:2}function o5(){var e=Qe.p;return e!==0?e:(e=window.event,e===void 0?32:BM(e.type))}function sO(e,t){var o=Qe.p;try{return Qe.p=e,t()}finally{Qe.p=o}}var Ja=Math.random().toString(36).slice(2),Do="__reactFiber$"+Ja,vr="__reactProps$"+Ja,Cc="__reactContainer$"+Ja,lO="__reactEvents$"+Ja,UU="__reactListeners$"+Ja,LU="__reactHandles$"+Ja,pO="__reactResources$"+Ja,Xf="__reactMarker$"+Ja,Nh="__reactLoad$"+Ja;function tg(e){delete e[Do],delete e[vr],delete e[UU],delete e[LU]}function Ks(e){var t;if(t=e[Do])return t;for(var o=e.parentNode;o;){if(t=o[Cc]||o[Do]){if(o=t.alternate,t.child!==null||o!==null&&o.child!==null)for(e=Rw(e);e!==null;){if(o=e[Do])return o;e=Rw(e)}return t}e=o,o=e.parentNode}return null}function Ec(e){if(e=e[Do]||e[Cc]){var t=e.tag;if(t===5||t===6||t===13||t===31||t===26||t===27||t===3)return e}return null}function mf(e){var t=e.tag;if(t===5||t===26||t===27||t===6)return e.stateNode;throw Error(F(33))}function tc(e){var t=e[pO];return t||(t=e[pO]={hoistableStyles:new Map,hoistableScripts:new Map}),t}function xo(e){e[Xf]=!0}function r5(e){e[Nh]=void 0}var n5=new Set,a5={};function ul(e,t){fc(e,t),fc(e+"Capt
Line truncated
|
||||
`).replace(CL,"")}function mM(e,t){return t=hw(t),hw(e)===t}function it(e,t,o,r,n,a){switch(o){case"children":if(typeof r=="string")t==="body"||t==="textarea"&&r===""||dc(e,r);else if(typeof r=="number"||typeof r=="bigint")t!=="body"&&dc(e,""+r);else return;break;case"className":Vy(e,"class",r);break;case"tabIndex":Vy(e,"tabindex",r);break;case"dir":case"role":case"viewBox":case"width":case"height":Vy(e,o,r);break;case"style":u5(e,r,a);return;case"data":if(t!=="object"){Vy(e,"data",r);break}case"src":case"href":if(r===""&&(t!=="a"||o!=="href")){e.removeAttribute(o);break}if(r==null||typeof r=="function"||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=sh(r),e.setAttribute(o,r);break;case"action":case"formAction":if(typeof r=="function"){e.setAttribute(o,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof a=="function"&&(o==="formAction"?(t!=="input"&&it(e,t,"name",n.name,n,null),it(e,t,"formEncType",n.formEncType,n,null),it(e,t,"formMethod",n.formMethod,n,null),it(e,t,"formTarget",n.formTarget,n,null)):(it(e,t,"encType",n.encType,n,null),it(e,t,"method",n.method,n,null),it(e,t,"target",n.target,n,null)));if(r==null||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=sh(r),e.setAttribute(o,r);break;case"onClick":r!=null&&(e.onclick=ia);return;case"onScroll":r!=null&&Ie("scroll",e);return;case"onScrollEnd":r!=null&&Ie("scrollend",e);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(F(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(F(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"multiple":e.multiple=r&&typeof r!="function"&&typeof r!="symbol";break;case"muted":e.muted=r&&typeof r!="function"&&typeof r!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(r==null||typeof r=="function"||typeof r=="boolean"||typeof r=="symbol"){e.removeAttribute("xlink:href");break}o=sh(r),e.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",o);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"credentialless":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":r&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,""):e.removeAttribute(o);break;case"capture":case"download":r===!0?e.setAttribute(o,""):r!==!1&&r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"cols":case"rows":case"size":case"span":r!=null&&typeof r!="function"&&typeof r!="symbol"&&!isNaN(r)&&1<=r?e.setAttribute(o,r):e.removeAttribute(o);break;case"rowSpan":case"start":r==null||typeof r=="function"||typeof r=="symbol"||isNaN(r)?e.removeAttribute(o):e.setAttribute(o,r);break;case"popover":Ie("beforetoggle",e),Ie("toggle",e),ih(e,"popover",r);break;case"xlinkActuate":$a(e,"http://www.w3.org/1999/xlink","xlink:actuate",r);break;case"xlinkArcrole":$a(e,"http://www.w3.org/1999/xlink","xlink:arcrole",r);break;case"xlinkRole":$a(e,"http://www.w3.org/1999/xlink","xlink:role",r);break;case"xlinkShow":$a(e,"http://www.w3.org/1999/xlink","xlink:show",r);break;case"xlinkTitle":$a(e,"http://www.w3.org/1999/xlink","xlink:title",r);break;case"xlinkType":$a(e,"http://www.w3.org/1999/xlink","xlink:type",r);break;case"xmlBase":$a(e,"http://www.w3.org/XML/1998/namespace","xml:base",r);break;case"xmlLang":$a(e,"http://www.w3.org/XML/1998/namespace","xml:lang",r);break;case"xmlSpace":$a(e,"http://www.w3.org/XML/1998/namespace","xml:space",r);break;case"is":ih(e,"is",r);break;case"innerText":case"textContent":return;default:if(!(2<o.length)||o[0]!=="o"&&o[0]!=="O"||o[1]!=="n"&&o[1]!=="N")o=qU.get(o)||o,ih(e,o,r);else return}Ke=!0}function j0(e,t,o,r,n,a){switch(o){case"style":u5(e,r,a);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(F(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(F(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"children":if(typeof r=="string")dc(e,r);else if(typeof r=="number"||typeof r=="bigint")dc(e,""+r);else return;break;case"onScroll":r!=null&&Ie("scroll",e);return;case"onScrollEnd":r!=null&&Ie("scrollend",e);return;case"onClick":r
Line truncated
|
||||
`)),(BP!==void 0?Pk:vk)(d,s,l,p,c)}}var NF=rT();function Sk(e,t=Number.MIN_SAFE_INTEGER,o=Number.MAX_SAFE_INTEGER){return Math.max(t,Math.min(e,o))}var nT=Sk;function iT(e,t=0,o=1){return nT(e,t,o)}function Ck(e){e=e.slice(1);let t=new RegExp(`.{1,${e.length>=6?2:1}}`,"g"),o=e.match(t);return o&&o[0].length===1&&(o=o.map(r=>r+r)),o?`rgb${o.length===4?"a":""}(${o.map((r,n)=>n<3?parseInt(r,16):Math.round(parseInt(r,16)/255*1e3)/1e3).join(", ")})`:""}function si(e){if(e.type)return e;if(e.charAt(0)==="#")return si(Ck(e));let t=e.indexOf("("),o=e.substring(0,t);if(!["rgb","rgba","hsl","hsla","color"].includes(o))throw new Error(uo(9,e));let r=e.substring(t+1,e.length-1),n;if(o==="color"){if(r=r.split(" "),n=r.shift(),r.length===4&&r[3].charAt(0)==="/"&&(r[3]=r[3].slice(1)),!["srgb","display-p3","a98-rgb","prophoto-rgb","rec-2020"].includes(n))throw new Error(uo(10,n))}else r=r.split(",");return r=r.map(a=>parseFloat(a)),{type:o,values:r,colorSpace:n}}var Ek=e=>{let t=si(e);return t.values.slice(0,3).map((o,r)=>t.type.includes("hsl")&&r!==0?`${o}%`:o).join(" ")},Ll=(e,t)=>{try{return Ek(e)}catch{return e}};function Kd(e){let{type:t,colorSpace:o}=e,{values:r}=e;return t.includes("rgb")?r=r.map((n,a)=>a<3?parseInt(n,10):n):t.includes("hsl")&&(r[1]=`${r[1]}%`,r[2]=`${r[2]}%`),t.includes("color")?r=`${o} ${r.join(" ")}`:r=`${r.join(", ")}`,`${t}(${r})`}function sT(e){e=si(e);let{values:t}=e,o=t[0],r=t[1]/100,n=t[2]/100,a=r*Math.min(n,1-n),i=(p,c=(p+o/30)%12)=>n-a*Math.max(Math.min(c-3,9-c,1),-1),s="rgb",l=[Math.round(i(0)*255),Math.round(i(8)*255),Math.round(i(4)*255)];return e.type==="hsla"&&(s+="a",l.push(t[3])),Kd({type:s,values:l})}function aT(e){e=si(e);let t=e.type==="hsl"||e.type==="hsla"?si(sT(e)).values:e.values;return t=t.map(o=>(e.type!=="color"&&(o/=255),o<=.03928?o/12.92:((o+.055)/1.055)**2.4)),Number((.2126*t[0]+.7152*t[1]+.0722*t[2]).toFixed(3))}function UP(e,t){let o=aT(e),r=aT(t);return(Math.max(o,r)+.05)/(Math.min(o,r)+.05)}function li(e,t){return e=si(e),t=iT(t),(e.type==="rgb"||e.type==="hsl")&&(e.type+="a"),e.type==="color"?e.values[3]=`/${t}`:e.values[3]=t,Kd(e)}function pi(e,t,o){try{return li(e,t)}catch{return e}}function Il(e,t){if(e=si(e),t=iT(t),e.type.includes("hsl"))e.values[2]*=1-t;else if(e.type.includes("rgb")||e.type.includes("color"))for(let o=0;o<3;o+=1)e.values[o]*=1-t;return Kd(e)}function Je(e,t,o){try{return Il(e,t)}catch{return e}}function $l(e,t){if(e=si(e),t=iT(t),e.type.includes("hsl"))e.values[2]+=(100-e.values[2])*t;else if(e.type.includes("rgb"))for(let o=0;o<3;o+=1)e.values[o]+=(255-e.values[o])*t;else if(e.type.includes("color"))for(let o=0;o<3;o+=1)e.values[o]+=(1-e.values[o])*t;return Kd(e)}function et(e,t,o){try{return $l(e,t)}catch{return e}}function Xd(e,t=.15){return aT(e)>.5?Il(e,t):$l(e,t)}function Zc(e,t,o){try{return Xd(e,t)}catch{return e}}var JP=C(I(),1);var $P=C(I(),1);var LP=C(I(),1),Rk=LP.createContext(null),Qd=Rk;var lT=C(I(),1);function xa(){return lT.useContext(Qd)}var Ok=typeof Symbol=="function"&&Symbol.for,IP=Ok?Symbol.for("mui.nested"):"__THEME_NESTED__";var HP=C(z(),1);function wk(e,t){return typeof t=="function"?t(e):{...e,...t}}function Nk(e){let{children:t,theme:o}=e,r=xa(),n=$P.useMemo(()=>{let a=r===null?{...o}:wk(r,o);return a!=null&&(a[IP]=r!==null),a},[o,r]);return(0,HP.jsx)(Qd.Provider,{value:n,children:t})}var Zd=Nk;var Jd=C(I(),1);var VP=C(z(),1),FP=Jd.createContext();function Mk({value:e,...t}){return(0,VP.jsx)(FP.Provider,{value:e??!0,...t})}var ci=()=>Jd.useContext(FP)??!1,qP=Mk;var em=C(I(),1);var GP=C(z(),1),YP=em.createContext(void 0);function Ak({value:e,children:t}){return(0,GP.jsx)(YP.Provider,{value:e,children:t})}function kk(e){let{theme:t,name:o,props:r}=e;if(!t||!t.components||!t.components[o])return r;let n=t.components[o];return n.defaultProps?Wn(n.defaultProps,r,t.components.mergeClassNameAndStyle):!n.styleOverrides&&!n.variants?Wn(n,r,t.components.mergeClassNameAndStyle):r}function pT({props:e,name:t}){let o=em.useContext(YP);return kk({props:e,name:t,theme:{components:o}})}var tm=Ak;var Jc=C(I(),1),WP=0;function Dk(e){let[t,o]=Jc.useState(e),r=e||t;return Jc.useEffect(()=>{t==null&&(WP+=1,o(`mui-${WP}`))},[t]),r}var _k={...Jc},KP=_k.useId;function Wr(e){if(KP!==void 0){let t=KP();return e??t}return Dk(e)}var XP=C(z(),1);function cT(e){let t=ba(),o=Wr()||"",{modularCssLayers:r}=e,n="mui.global, mui.components, mui.theme, mui.custom, mui.sx";return!r||t!==null?n="":typeof r=="string"?n=r.replace(/mui(?!\.)/g,n):n=`@layer ${n};`,Xt(()=>{let a=document.querySelector("head");if(!a)return;let i=a.firstChild;if(n){if(i&&i.hasAttribute?.("data-mui-layer-order")&&i.getAttribute("data-mui-layer-order")===o)return;let s=document.createElement("style");s.setAttribute("data-mui-layer-order",o),s.textContent=n,a.prepend(s)}else a.querySelector(`style[data-mui-layer-order="${o}"]`)?.remove()},[n,o]),n?(0,XP.jsx)(_l,{styles:n}):null}var Hl=C(z(),1),QP={};function ZP(e,t,o,r=!1){return JP.useMemo(()=>{let n=e&&t[e]||t;if(typeof o=="f
Line truncated
|
||||
${s}.classList.add('${f}'.replace('%s', colorScheme));`}let d=c.match(/\[([^[\]]+)\]/);if(d){let[f,u]=d[1].split("=");u||(p+=`${s}.removeAttribute('${f}'.replace('%s', light));
|
||||
${s}.removeAttribute('${f}'.replace('%s', dark));`),p+=`
|
||||
${s}.setAttribute('${f}'.replace('%s', colorScheme), ${u?`${u}.replace('%s', colorScheme)`:'""'});`}else c!==".%s"&&(p+=`${s}.setAttribute('${c}', colorScheme);`);return(0,KP.jsx)("script",{suppressHydrationWarning:!0,nonce:typeof window>"u"?l:"",dangerouslySetInnerHTML:{__html:`(function() {
|
||||
${s}.setAttribute('${f}'.replace('%s', colorScheme), ${u?`${u}.replace('%s', colorScheme)`:'""'});`}else c!==".%s"&&(p+=`${s}.setAttribute('${c}', colorScheme);`);return(0,tS.jsx)("script",{suppressHydrationWarning:!0,nonce:typeof window>"u"?l:"",dangerouslySetInnerHTML:{__html:`(function() {
|
||||
try {
|
||||
let colorScheme = '';
|
||||
const mode = localStorage.getItem('${n}') || '${t}';
|
||||
@@ -34,15 +34,15 @@ try {
|
||||
if (colorScheme) {
|
||||
${p}
|
||||
}
|
||||
} catch(e){}})();`}},"mui-color-scheme-init")}var xo=C(I(),1);function wD(){}var ND=({key:e,storageWindow:t})=>(!t&&typeof window<"u"&&(t=window),{get(o){if(typeof window>"u")return;if(!t)return o;let r;try{r=t.localStorage.getItem(e)}catch{}return r||o},set:o=>{if(t)try{t.localStorage.setItem(e,o)}catch{}},subscribe:o=>{if(!t)return wD;let r=n=>{let a=n.newValue;n.key===e&&o(a)};return t.addEventListener("storage",r),()=>{t.removeEventListener("storage",r)}}}),WP=ND;function aT(){}function XP(e){if(typeof window<"u"&&typeof window.matchMedia=="function"&&e==="system")return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function QP(e,t){if(e.mode==="light"||e.mode==="system"&&e.systemMode==="light")return t("light");if(e.mode==="dark"||e.mode==="system"&&e.systemMode==="dark")return t("dark")}function MD(e){return QP(e,t=>{if(t==="light")return e.lightColorScheme;if(t==="dark")return e.darkColorScheme})}function iT(e){let{defaultMode:t="light",defaultLightColorScheme:o,defaultDarkColorScheme:r,supportedColorSchemes:n=[],modeStorageKey:a=qc,colorSchemeStorageKey:i=Gc,storageWindow:s=typeof window>"u"?void 0:window,storageManager:l=WP,noSsr:p=!1}=e,c=n.join(","),m=n.length>1,f=xo.useMemo(()=>l?.({key:a,storageWindow:s}),[l,a,s]),u=xo.useMemo(()=>l?.({key:`${i}-light`,storageWindow:s}),[l,i,s]),g=xo.useMemo(()=>l?.({key:`${i}-dark`,storageWindow:s}),[l,i,s]),[v,x]=xo.useState(()=>{let R=f?.get(t)||t,w=u?.get(o)||o,O=g?.get(r)||r;return{mode:R,systemMode:XP(R),lightColorScheme:w,darkColorScheme:O}}),[d,y]=xo.useState(p||!m);xo.useEffect(()=>{y(!0)},[]);let h=MD(v),T=xo.useCallback(R=>{x(w=>{if(R===w.mode)return w;let O=R??t;return f?.set(O),{...w,mode:O,systemMode:XP(O)}})},[f,t]),P=xo.useCallback(R=>{R?typeof R=="string"?R&&!c.includes(R)?console.error(`\`${R}\` does not exist in \`theme.colorSchemes\`.`):x(w=>{let O={...w};return QP(w,N=>{N==="light"&&(u?.set(R),O.lightColorScheme=R),N==="dark"&&(g?.set(R),O.darkColorScheme=R)}),O}):x(w=>{let O={...w},N=R.light===null?o:R.light,b=R.dark===null?r:R.dark;return N&&(c.includes(N)?(O.lightColorScheme=N,u?.set(N)):console.error(`\`${N}\` does not exist in \`theme.colorSchemes\`.`)),b&&(c.includes(b)?(O.darkColorScheme=b,g?.set(b)):console.error(`\`${b}\` does not exist in \`theme.colorSchemes\`.`)),O}):x(w=>(u?.set(o),g?.set(r),{...w,lightColorScheme:o,darkColorScheme:r}))},[c,u,g,o,r]),S=xo.useCallback(R=>{v.mode==="system"&&x(w=>{let O=R?.matches?"dark":"light";return w.systemMode===O?w:{...w,systemMode:O}})},[v.mode]),E=xo.useRef(S);return E.current=S,xo.useEffect(()=>{if(typeof window.matchMedia!="function"||!m)return;let R=(...O)=>E.current(...O),w=window.matchMedia("(prefers-color-scheme: dark)");return w.addListener(R),R(w),()=>{w.removeListener(R)}},[m]),xo.useEffect(()=>{if(m){let R=f?.subscribe(N=>{(!N||["light","dark","system"].includes(N))&&T(N||t)})||aT,w=u?.subscribe(N=>{(!N||c.match(N))&&P({light:N})})||aT,O=g?.subscribe(N=>{(!N||c.match(N))&&P({dark:N})})||aT;return()=>{R(),w(),O()}}},[P,T,c,t,s,m,f,u,g]),{...v,mode:d?v.mode:void 0,systemMode:d?v.systemMode:void 0,colorScheme:d?h:void 0,setMode:T,setColorScheme:P}}var jl=C(U(),1),AD="*{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}";function Wd(e){let{themeId:t,theme:o={},modeStorageKey:r=qc,colorSchemeStorageKey:n=Gc,disableTransitionOnChange:a=!1,defaultColorScheme:i,resolveTheme:s}=e,l={allColorSchemes:[],colorScheme:void 0,darkColorScheme:void 0,lightColorScheme:void 0,mode:void 0,setColorScheme:()=>{},setMode:()=>{},systemMode:void 0},p=Po.createContext(void 0),c=()=>Po.useContext(p)||l,m={},f={};function u(d){let{children:y,theme:h,modeStorageKey:T=r,colorSchemeStorageKey:P=n,disableTransitionOnChange:S=a,storageManager:E,storageWindow:R=typeof window>"u"?void 0:window,documentNode:w=typeof document>"u"?void 0:document,colorSchemeNode:O=typeof document>"u"?void 0:document.documentElement,disableNestedContext:N=!1,disableStyleSheetGeneration:b=!1,defaultMode:M="system",forceThemeRerender:A=!1,noSsr:_}=d,k=Po.useRef(!1),W=ga(),re=Po.useContext(p),F=!!re&&!N,me=Po.useMemo(()=>h||(typeof o=="function"?o():o),[h]),ie=me[t],ue=ie||me,{colorSchemes:ne=m,components:Ee=f,cssVarPrefix:le}=ue,oe=Object.keys(ne).filter(Ye=>!!ne[Ye]).join(","),ye=Po.useMemo(()=>oe.split(","),[oe]),ge=typeof i=="string"?i:i.light,Te=typeof i=="string"?i:i.dark,se=ne[ge]&&ne[Te]?M:ne[ue.defaultColorScheme]?.palette?.mode||ue.palette?.mode,{mode:de,setMode:be,systemMode:$,lightColorScheme:z,darkColorScheme:xe,colorScheme:Oe,setColorScheme:Pe}=iT({supportedColorSchemes:ye,defaultLightColorScheme:ge,defaultDarkColorScheme:Te,modeStorageKey:T,colorSchemeStorageKey:P,defaultMode:se,storageManager:E,storageWindow:R,noSsr:_}),ke=de,qe=Oe;F&&(ke=re.mode,qe=re.colorScheme);let $e=qe||ue.defaultColorScheme;ue.vars&&!A&&($e=ue.defaultColorScheme);let Ne=Po.useMemo(()=>{let Ye=ue.generateThemeVars?.()||ue.Line truncated
|
||||
} catch(e){}})();`}},"mui-color-scheme-init")}var Oo=C(I(),1);function Bk(){}var Uk=({key:e,storageWindow:t})=>(!t&&typeof window<"u"&&(t=window),{get(o){if(typeof window>"u")return;if(!t)return o;let r;try{r=t.localStorage.getItem(e)}catch{}return r||o},set:o=>{if(t)try{t.localStorage.setItem(e,o)}catch{}},subscribe:o=>{if(!t)return Bk;let r=n=>{let a=n.newValue;n.key===e&&o(a)};return t.addEventListener("storage",r),()=>{t.removeEventListener("storage",r)}}}),oS=Uk;function fT(){}function rS(e){if(typeof window<"u"&&typeof window.matchMedia=="function"&&e==="system")return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function nS(e,t){if(e.mode==="light"||e.mode==="system"&&e.systemMode==="light")return t("light");if(e.mode==="dark"||e.mode==="system"&&e.systemMode==="dark")return t("dark")}function Lk(e){return nS(e,t=>{if(t==="light")return e.lightColorScheme;if(t==="dark")return e.darkColorScheme})}function dT(e){let{defaultMode:t="light",defaultLightColorScheme:o,defaultDarkColorScheme:r,supportedColorSchemes:n=[],modeStorageKey:a=eu,colorSchemeStorageKey:i=tu,storageWindow:s=typeof window>"u"?void 0:window,storageManager:l=oS,noSsr:p=!1}=e,c=n.join(","),d=n.length>1,f=Oo.useMemo(()=>l?.({key:a,storageWindow:s}),[l,a,s]),u=Oo.useMemo(()=>l?.({key:`${i}-light`,storageWindow:s}),[l,i,s]),g=Oo.useMemo(()=>l?.({key:`${i}-dark`,storageWindow:s}),[l,i,s]),[x,v]=Oo.useState(()=>{let R=f?.get(t)||t,w=u?.get(o)||o,O=g?.get(r)||r;return{mode:R,systemMode:rS(R),lightColorScheme:w,darkColorScheme:O}}),[m,y]=Oo.useState(p||!d);Oo.useEffect(()=>{y(!0)},[]);let h=Lk(x),T=Oo.useCallback(R=>{v(w=>{if(R===w.mode)return w;let O=R??t;return f?.set(O),{...w,mode:O,systemMode:rS(O)}})},[f,t]),P=Oo.useCallback(R=>{R?typeof R=="string"?R&&!c.includes(R)?console.error(`\`${R}\` does not exist in \`theme.colorSchemes\`.`):v(w=>{let O={...w};return nS(w,A=>{A==="light"&&(u?.set(R),O.lightColorScheme=R),A==="dark"&&(g?.set(R),O.darkColorScheme=R)}),O}):v(w=>{let O={...w},A=R.light===null?o:R.light,b=R.dark===null?r:R.dark;return A&&(c.includes(A)?(O.lightColorScheme=A,u?.set(A)):console.error(`\`${A}\` does not exist in \`theme.colorSchemes\`.`)),b&&(c.includes(b)?(O.darkColorScheme=b,g?.set(b)):console.error(`\`${b}\` does not exist in \`theme.colorSchemes\`.`)),O}):v(w=>(u?.set(o),g?.set(r),{...w,lightColorScheme:o,darkColorScheme:r}))},[c,u,g,o,r]),S=Oo.useCallback(R=>{x.mode==="system"&&v(w=>{let O=R?.matches?"dark":"light";return w.systemMode===O?w:{...w,systemMode:O}})},[x.mode]),E=Oo.useRef(S);return E.current=S,Oo.useEffect(()=>{if(typeof window.matchMedia!="function"||!d)return;let R=(...O)=>E.current(...O),w=window.matchMedia("(prefers-color-scheme: dark)");return w.addListener(R),R(w),()=>{w.removeListener(R)}},[d]),Oo.useEffect(()=>{if(d){let R=f?.subscribe(A=>{(!A||["light","dark","system"].includes(A))&&T(A||t)})||fT,w=u?.subscribe(A=>{(!A||c.match(A))&&P({light:A})})||fT,O=g?.subscribe(A=>{(!A||c.match(A))&&P({dark:A})})||fT;return()=>{R(),w(),O()}}},[P,T,c,t,s,d,f,u,g]),{...x,mode:m?x.mode:void 0,systemMode:m?x.systemMode:void 0,colorScheme:m?h:void 0,setMode:T,setColorScheme:P}}var Fl=C(z(),1),Ik="*{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}";function rm(e){let{themeId:t,theme:o={},modeStorageKey:r=eu,colorSchemeStorageKey:n=tu,disableTransitionOnChange:a=!1,defaultColorScheme:i,resolveTheme:s}=e,l={allColorSchemes:[],colorScheme:void 0,darkColorScheme:void 0,lightColorScheme:void 0,mode:void 0,setColorScheme:()=>{},setMode:()=>{},systemMode:void 0},p=wo.createContext(void 0),c=()=>wo.useContext(p)||l,d={},f={};function u(m){let{children:y,theme:h,modeStorageKey:T=r,colorSchemeStorageKey:P=n,disableTransitionOnChange:S=a,storageManager:E,storageWindow:R=typeof window>"u"?void 0:window,documentNode:w=typeof document>"u"?void 0:document,colorSchemeNode:O=typeof document>"u"?void 0:document.documentElement,disableNestedContext:A=!1,disableStyleSheetGeneration:b=!1,defaultMode:N="system",forceThemeRerender:M=!1,noSsr:_}=m,D=wo.useRef(!1),K=xa(),ee=wo.useContext(p),q=!!ee&&!A,ye=wo.useMemo(()=>h||(typeof o=="function"?o():o),[h]),se=ye[t],ce=se||ye,{colorSchemes:oe=d,components:Ce=f,cssVarPrefix:pe}=ce,re=Object.keys(oe).filter(Ge=>!!oe[Ge]).join(","),Te=wo.useMemo(()=>re.split(","),[re]),he=typeof i=="string"?i:i.light,Ee=typeof i=="string"?i:i.dark,le=oe[he]&&oe[Ee]?N:oe[ce.defaultColorScheme]?.palette?.mode||ce.palette?.mode,{mode:fe,setMode:ge,systemMode:$,lightColorScheme:U,darkColorScheme:Pe,colorScheme:Me,setColorScheme:Se}=dT({supportedColorSchemes:Te,defaultLightColorScheme:he,defaultDarkColorScheme:Ee,modeStorageKey:T,colorSchemeStorageKey:P,defaultMode:le,storageManager:E,storageWindow:R,noSsr:_}),Oe=fe,Ve=Me;q&&(Oe=ee.mode,Ve=ee.colorScheme);let Ze=Ve||ce.defaultColorScheme;ce.vars&&!M&&(Ze=ce.defaultColorScheme);let Fe=wo.useMemo(()=>{let Ge=ce.generateThemeVars?.()||ce.Line truncated
|
||||
|
||||
const theme = ${JSON.stringify(t,null,2)};
|
||||
|
||||
theme.breakpoints = createBreakpoints(theme.breakpoints || {});
|
||||
theme.transitions = createTransitions(theme.transitions || {});
|
||||
|
||||
export default theme;`}function fS(e){return typeof e=="number"?`${(e*100).toFixed(0)}%`:`calc((${e}) * 100%)`}var nk=e=>{if(!Number.isNaN(+e))return+e;let t=e.match(/\d*\.?\d+/g);if(!t)return 0;let o=0;for(let r=0;r<t.length;r+=1)o+=+t[r];return o};function ak(e){Object.assign(e,{alpha(t,o){let r=this||e;return r.colorSpace?`oklch(from ${t} l c h / ${typeof o=="string"?`calc(${o})`:o})`:r.vars?`rgba(${t.replace(/var\(--([^,\s)]+)(?:,[^)]+)?\)+/g,"var(--$1Channel)")} / ${typeof o=="string"?`calc(${o})`:o})`:ri(t,nk(o))},lighten(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #fff ${fS(o)})`:kl(t,o)},darken(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #000 ${fS(o)})`:Dl(t,o)}})}function ik(e={},...t){let{breakpoints:o,mixins:r={},spacing:n,palette:a={},transitions:i={},typography:s={},shape:l,colorSpace:p,...c}=e;if(e.vars&&e.generateThemeVars===void 0)throw new Error(io(20));let m=ls({...a,colorSpace:p}),f=bn(e),u=Xe(f,{mixins:cT(f.breakpoints,r),palette:m,shadows:pS.slice(),typography:Kc(m,s),transitions:fT(i),zIndex:{...uS}});return u=Xe(u,c),u=t.reduce((g,v)=>Xe(g,v),u),u.unstable_sxConfig={...Tn,...c?.unstable_sxConfig},u.unstable_sx=function(v){return lr({sx:v,theme:this})},u.toRuntimeSource=om,ak(u),u}var Wc=ik;function Ul(e){let t;return e<1?t=5.11916*e**2:t=4.5*Math.log(e+1)+2,Math.round(t*10)/1e3}var sk=[...Array(25)].map((e,t)=>{if(t===0)return"none";let o=Ul(t);return`linear-gradient(rgba(255 255 255 / ${o}), rgba(255 255 255 / ${o}))`});function dT(e){return{inputPlaceholder:e==="dark"?.5:.42,inputUnderline:e==="dark"?.7:.42,switchTrackDisabled:e==="dark"?.2:.12,switchTrack:e==="dark"?.3:.38}}function mT(e){return e==="dark"?sk:[]}function yT(e){let{palette:t={mode:"light"},opacity:o,overlays:r,colorSpace:n,...a}=e,i=ls({...t,colorSpace:n});return{palette:i,opacity:{...dT(i.mode),...o},overlays:r||mT(i.mode),...a}}function hT(e){return!!e[0].match(/(cssVarPrefix|colorSchemeSelector|modularCssLayers|rootSelector|typography|mixins|breakpoints|direction|transitions)/)||!!e[0].match(/sxConfig$/)||e[0]==="palette"&&!!e[1]?.match(/(mode|contrastThreshold|tonalOffset)/)}var lk=e=>[...[...Array(25)].map((t,o)=>`--${e?`${e}-`:""}overlays-${o}`),`--${e?`${e}-`:""}palette-AppBar-darkBg`,`--${e?`${e}-`:""}palette-AppBar-darkColor`],dS=lk;var mS=e=>(t,o)=>{let r=e.rootSelector||":root",n=e.colorSchemeSelector,a=n;if(n==="class"&&(a=".%s"),n==="data"&&(a="[data-%s]"),n?.startsWith("data-")&&!n.includes("%s")&&(a=`[${n}="%s"]`),e.defaultColorScheme===t){if(t==="dark"){let i={};return dS(e.cssVarPrefix).forEach(s=>{i[s]=o[s],delete o[s]}),a==="media"?{[r]:o,"@media (prefers-color-scheme: dark)":{[r]:i}}:a?{[a.replace("%s",t)]:i,[`${r}, ${a.replace("%s",t)}`]:o}:{[r]:{...o,...i}}}if(a&&a!=="media")return`${r}, ${a.replace("%s",String(t))}`}else if(t){if(a==="media")return{[`@media (prefers-color-scheme: ${String(t)})`]:{[r]:o}};if(a)return a.replace("%s",String(t))}return r};function pk(e,t){t.forEach(o=>{e[o]||(e[o]={})})}function H(e,t,o){!e[t]&&o&&(e[t]=o)}function Xc(e){return typeof e!="string"||!e.startsWith("hsl")?e:eT(e)}function Ta(e,t){`${t}Channel`in e||(e[`${t}Channel`]=Al(Xc(e[t]),`MUI: Can't create \`palette.${t}Channel\` because \`palette.${t}\` is not one of these formats: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla(), color().
|
||||
To suppress this warning, you need to explicitly provide the \`palette.${t}Channel\` as a string (in rgb format, for example "12 12 12") or undefined if you want to remove the channel token.`))}function ck(e){return typeof e=="number"?`${e}px`:typeof e=="string"||typeof e=="function"||Array.isArray(e)?e:"8px"}var Gn=e=>{try{return e()}catch{}},uk=(e="mui")=>Xd(e);function gT(e,t,o,r,n){if(!o)return;o=o===!0?{}:o;let a=n==="dark"?"dark":"light";if(!r){t[n]=yT({...o,palette:{mode:a,...o?.palette},colorSpace:e});return}let{palette:i,...s}=Wc({...r,palette:{mode:a,...o?.palette},colorSpace:e});return t[n]={...o,palette:i,opacity:{...dT(a),...o?.opacity},overlays:o?.overlays||mT(a)},s}function TT(e={},...t){let{colorSchemes:o={light:!0},defaultColorScheme:r,disableCssColorScheme:n=!1,cssVarPrefix:a="mui",nativeColor:i=!1,shouldSkipGeneratingVar:s=hT,colorSchemeSelector:l=o.light&&o.dark?"media":void 0,rootSelector:p=":root",...c}=e,m=Object.keys(o)[0],f=r||(o.light&&m!=="light"?"light":m),u=uk(a),{[f]:g,light:v,dark:x,...d}=o,y={...d},h=g;if((f==="dark"&&!("dark"in o)||f==="light"&&!("light"in o))&&(h=!0),!h)throw new Error(io(21,f));let T;i&&(T="oklch");let P=gT(T,y,h,c,f);v&&!y.light&&gT(T,y,v,void 0,"light"),x&&!y.dark&&gT(T,y,x,void 0,"dark");let S={defaultColorScheme:f,...P,cssVarPrefix:a,colorSchemeSelector:l,rootSelector:p,getCssVar:u,colorSchemes:y,font:{...tm(P.typography),...P.font},spacing:ck(c.spacing)};Object.keys(S.colorSchemes).forEach(N=>{let b=S.colorSchemes[N].palette,M=_=>{let k=_.split("-"),W=k[1],re=k[2];return u(_,b[W][re])};b.mode==="light"&&(H(b.common,"background","#fff"),H(b.common,"onBackground","#000")),b.mode==="dark"&&(H(b.common,"background","#000"),H(b.common,"onBackground","#fff"));function A(_,k,W){if(T){let re;return _===ni&&(re=`transparent ${((1-W)*100).toFixed(0)}%`),_===et&&(re=`#000 ${(W*100).toFixed(0)}%`),_===tt&&(re=`#fff ${(W*100).toFixed(0)}%`),`color-mix(in ${T}, ${k}, ${re})`}return _(k,W)}if(pk(b,["Alert","AppBar","Avatar","Button","Chip","FilledInput","LinearProgress","Skeleton","Slider","SnackbarContent","SpeedDialAction","StepConnector","StepContent","Switch","TableCell","Tooltip"]),b.mode==="light"){H(b.Alert,"errorColor",A(et,i?u("palette-error-light"):b.error.light,.6)),H(b.Alert,"infoColor",A(et,i?u("palette-info-light"):b.info.light,.6)),H(b.Alert,"successColor",A(et,i?u("palette-success-light"):b.success.light,.6)),H(b.Alert,"warningColor",A(et,i?u("palette-warning-light"):b.warning.light,.6)),H(b.Alert,"errorFilledBg",M("palette-error-main")),H(b.Alert,"infoFilledBg",M("palette-info-main")),H(b.Alert,"successFilledBg",M("palette-success-main")),H(b.Alert,"warningFilledBg",M("palette-warning-main")),H(b.Alert,"errorFilledColor",Gn(()=>b.getContrastText(b.error.main))),H(b.Alert,"infoFilledColor",Gn(()=>b.getContrastText(b.info.main))),H(b.Alert,"successFilledColor",Gn(()=>b.getContrastText(b.success.main))),H(b.Alert,"warningFilledColor",Gn(()=>b.getContrastText(b.warning.main))),H(b.Alert,"errorStandardBg",A(tt,i?u("palette-error-light"):b.error.light,.9)),H(b.Alert,"infoStandardBg",A(tt,i?u("palette-info-light"):b.info.light,.9)),H(b.Alert,"successStandardBg",A(tt,i?u("palette-success-light"):b.success.light,.9)),H(b.Alert,"warningStandardBg",A(tt,i?u("palette-warning-light"):b.warning.light,.9)),H(b.Alert,"errorIconColor",M("palette-error-main")),H(b.Alert,"infoIconColor",M("palette-info-main")),H(b.Alert,"successIconColor",M("palette-success-main")),H(b.Alert,"warningIconColor",M("palette-warning-main")),H(b.AppBar,"defaultBg",M("palette-grey-100")),H(b.Avatar,"defaultBg",M("palette-grey-400")),H(b.Button,"inheritContainedBg",M("palette-grey-300")),H(b.Button,"inheritContainedHoverBg",M("palette-grey-A100")),H(b.Chip,"defaultBorder",M("palette-grey-400")),H(b.Chip,"defaultAvatarColor",M("palette-grey-700")),H(b.Chip,"defaultIconColor",M("palette-grey-700")),H(b.FilledInput,"bg","rgba(0, 0, 0, 0.06)"),H(b.FilledInput,"hoverBg","rgba(0, 0, 0, 0.09)"),H(b.FilledInput,"disabledBg","rgba(0, 0, 0, 0.12)"),H(b.LinearProgress,"primaryBg",A(tt,i?u("palette-primary-main"):b.primary.main,.62)),H(b.LinearProgress,"secondaryBg",A(tt,i?u("palette-secondary-main"):b.secondary.main,.62)),H(b.LinearProgress,"errorBg",A(tt,i?u("palette-error-main"):b.error.main,.62)),H(b.LinearProgress,"infoBg",A(tt,i?u("palette-info-main"):b.info.main,.62)),H(b.LinearProgress,"successBg",A(tt,i?u("palette-success-main"):b.success.main,.62)),H(b.LinearProgress,"warningBg",A(tt,i?u("palette-warning-light"):b.warning.main,.62)),H(b.Skeleton,"bg",T?A(ni,i?u("palette-text-primary"):b.text.primary,.11):`rgba(${M("palette-text-primaryChannel")} / 0.11)`),H(b.Slider,"primaryTrack",A(tt,i?u("palette-primary-main"):b.primary.main,.62)),H(b.Slider,"secondaryTrack",A(tt,i?u("palette-secondary-main"):b.secondary.main,.62)),H(b.Slider,"errorTrack",A(tt,i?u("palette-error-main"):b.error.main,.62)),H(b.Slider,"infoTrack",A(tt,i?u("palette-info-main"):b.info.main,.62)),H(b.Slider,"successTrack",A(tt,iLine truncated
|
||||
export default theme;`}function bS(e){return typeof e=="number"?`${(e*100).toFixed(0)}%`:`calc((${e}) * 100%)`}var dD=e=>{if(!Number.isNaN(+e))return+e;let t=e.match(/\d*\.?\d+/g);if(!t)return 0;let o=0;for(let r=0;r<t.length;r+=1)o+=+t[r];return o};function mD(e){Object.assign(e,{alpha(t,o){let r=this||e;return r.colorSpace?`oklch(from ${t} l c h / ${typeof o=="string"?`calc(${o})`:o})`:r.vars?`rgba(${t.replace(/var\(--([^,\s)]+)(?:,[^)]+)?\)+/g,"var(--$1Channel)")} / ${typeof o=="string"?`calc(${o})`:o})`:li(t,dD(o))},lighten(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #fff ${bS(o)})`:$l(t,o)},darken(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #000 ${bS(o)})`:Il(t,o)}})}function yD(e={},...t){let{breakpoints:o,mixins:r={},spacing:n,palette:a={},transitions:i={},typography:s={},shape:l,colorSpace:p,...c}=e;if(e.vars&&e.generateThemeVars===void 0)throw new Error(uo(20));let d=ys({...a,colorSpace:p}),f=vn(e),u=We(f,{mixins:gT(f.breakpoints,r),palette:d,shadows:hS.slice(),typography:ru(d,s),transitions:bT(i),zIndex:{...TS}});return u=We(u,c),u=t.reduce((g,x)=>We(g,x),u),u.unstable_sxConfig={...bn,...c?.unstable_sxConfig},u.unstable_sx=function(x){return ur({sx:x,theme:this})},u.toRuntimeSource=cm,mD(u),u}var nu=yD;function Gl(e){let t;return e<1?t=5.11916*e**2:t=4.5*Math.log(e+1)+2,Math.round(t*10)/1e3}var hD=[...Array(25)].map((e,t)=>{if(t===0)return"none";let o=Gl(t);return`linear-gradient(rgba(255 255 255 / ${o}), rgba(255 255 255 / ${o}))`});function vT(e){return{inputPlaceholder:e==="dark"?.5:.42,inputUnderline:e==="dark"?.7:.42,switchTrackDisabled:e==="dark"?.2:.12,switchTrack:e==="dark"?.3:.38}}function xT(e){return e==="dark"?hD:[]}function PT(e){let{palette:t={mode:"light"},opacity:o,overlays:r,colorSpace:n,...a}=e,i=ys({...t,colorSpace:n});return{palette:i,opacity:{...vT(i.mode),...o},overlays:r||xT(i.mode),...a}}function ST(e){return!!e[0].match(/(cssVarPrefix|colorSchemeSelector|modularCssLayers|rootSelector|typography|mixins|breakpoints|direction|transitions)/)||!!e[0].match(/sxConfig$/)||e[0]==="palette"&&!!e[1]?.match(/(mode|contrastThreshold|tonalOffset)/)}var gD=e=>[...[...Array(25)].map((t,o)=>`--${e?`${e}-`:""}overlays-${o}`),`--${e?`${e}-`:""}palette-AppBar-darkBg`,`--${e?`${e}-`:""}palette-AppBar-darkColor`],vS=gD;var xS=e=>(t,o)=>{let r=e.rootSelector||":root",n=e.colorSchemeSelector,a=n;if(n==="class"&&(a=".%s"),n==="data"&&(a="[data-%s]"),n?.startsWith("data-")&&!n.includes("%s")&&(a=`[${n}="%s"]`),e.defaultColorScheme===t){if(t==="dark"){let i={};return vS(e.cssVarPrefix).forEach(s=>{i[s]=o[s],delete o[s]}),a==="media"?{[r]:o,"@media (prefers-color-scheme: dark)":{[r]:i}}:a?{[a.replace("%s",t)]:i,[`${r}, ${a.replace("%s",t)}`]:o}:{[r]:{...o,...i}}}if(a&&a!=="media")return`${r}, ${a.replace("%s",String(t))}`}else if(t){if(a==="media")return{[`@media (prefers-color-scheme: ${String(t)})`]:{[r]:o}};if(a)return a.replace("%s",String(t))}return r};function TD(e,t){t.forEach(o=>{e[o]||(e[o]={})})}function H(e,t,o){!e[t]&&o&&(e[t]=o)}function au(e){return typeof e!="string"||!e.startsWith("hsl")?e:sT(e)}function Pa(e,t){`${t}Channel`in e||(e[`${t}Channel`]=Ll(au(e[t]),`MUI: Can't create \`palette.${t}Channel\` because \`palette.${t}\` is not one of these formats: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla(), color().
|
||||
To suppress this warning, you need to explicitly provide the \`palette.${t}Channel\` as a string (in rgb format, for example "12 12 12") or undefined if you want to remove the channel token.`))}function bD(e){return typeof e=="number"?`${e}px`:typeof e=="string"||typeof e=="function"||Array.isArray(e)?e:"8px"}var Kn=e=>{try{return e()}catch{}},vD=(e="mui")=>nm(e);function CT(e,t,o,r,n){if(!o)return;o=o===!0?{}:o;let a=n==="dark"?"dark":"light";if(!r){t[n]=PT({...o,palette:{mode:a,...o?.palette},colorSpace:e});return}let{palette:i,...s}=nu({...r,palette:{mode:a,...o?.palette},colorSpace:e});return t[n]={...o,palette:i,opacity:{...vT(a),...o?.opacity},overlays:o?.overlays||xT(a)},s}function ET(e={},...t){let{colorSchemes:o={light:!0},defaultColorScheme:r,disableCssColorScheme:n=!1,cssVarPrefix:a="mui",nativeColor:i=!1,shouldSkipGeneratingVar:s=ST,colorSchemeSelector:l=o.light&&o.dark?"media":void 0,rootSelector:p=":root",...c}=e,d=Object.keys(o)[0],f=r||(o.light&&d!=="light"?"light":d),u=vD(a),{[f]:g,light:x,dark:v,...m}=o,y={...m},h=g;if((f==="dark"&&!("dark"in o)||f==="light"&&!("light"in o))&&(h=!0),!h)throw new Error(uo(21,f));let T;i&&(T="oklch");let P=CT(T,y,h,c,f);x&&!y.light&&CT(T,y,x,void 0,"light"),v&&!y.dark&&CT(T,y,v,void 0,"dark");let S={defaultColorScheme:f,...P,cssVarPrefix:a,colorSchemeSelector:l,rootSelector:p,getCssVar:u,colorSchemes:y,font:{...pm(P.typography),...P.font},spacing:bD(c.spacing)};Object.keys(S.colorSchemes).forEach(A=>{let b=S.colorSchemes[A].palette,N=_=>{let D=_.split("-"),K=D[1],ee=D[2];return u(_,b[K][ee])};b.mode==="light"&&(H(b.common,"background","#fff"),H(b.common,"onBackground","#000")),b.mode==="dark"&&(H(b.common,"background","#000"),H(b.common,"onBackground","#fff"));function M(_,D,K){if(T){let ee;return _===pi&&(ee=`transparent ${((1-K)*100).toFixed(0)}%`),_===Je&&(ee=`#000 ${(K*100).toFixed(0)}%`),_===et&&(ee=`#fff ${(K*100).toFixed(0)}%`),`color-mix(in ${T}, ${D}, ${ee})`}return _(D,K)}if(TD(b,["Alert","AppBar","Avatar","Button","Chip","FilledInput","LinearProgress","Skeleton","Slider","SnackbarContent","SpeedDialAction","StepConnector","StepContent","Switch","TableCell","Tooltip"]),b.mode==="light"){H(b.Alert,"errorColor",M(Je,i?u("palette-error-light"):b.error.light,.6)),H(b.Alert,"infoColor",M(Je,i?u("palette-info-light"):b.info.light,.6)),H(b.Alert,"successColor",M(Je,i?u("palette-success-light"):b.success.light,.6)),H(b.Alert,"warningColor",M(Je,i?u("palette-warning-light"):b.warning.light,.6)),H(b.Alert,"errorFilledBg",N("palette-error-main")),H(b.Alert,"infoFilledBg",N("palette-info-main")),H(b.Alert,"successFilledBg",N("palette-success-main")),H(b.Alert,"warningFilledBg",N("palette-warning-main")),H(b.Alert,"errorFilledColor",Kn(()=>b.getContrastText(b.error.main))),H(b.Alert,"infoFilledColor",Kn(()=>b.getContrastText(b.info.main))),H(b.Alert,"successFilledColor",Kn(()=>b.getContrastText(b.success.main))),H(b.Alert,"warningFilledColor",Kn(()=>b.getContrastText(b.warning.main))),H(b.Alert,"errorStandardBg",M(et,i?u("palette-error-light"):b.error.light,.9)),H(b.Alert,"infoStandardBg",M(et,i?u("palette-info-light"):b.info.light,.9)),H(b.Alert,"successStandardBg",M(et,i?u("palette-success-light"):b.success.light,.9)),H(b.Alert,"warningStandardBg",M(et,i?u("palette-warning-light"):b.warning.light,.9)),H(b.Alert,"errorIconColor",N("palette-error-main")),H(b.Alert,"infoIconColor",N("palette-info-main")),H(b.Alert,"successIconColor",N("palette-success-main")),H(b.Alert,"warningIconColor",N("palette-warning-main")),H(b.AppBar,"defaultBg",N("palette-grey-100")),H(b.Avatar,"defaultBg",N("palette-grey-400")),H(b.Button,"inheritContainedBg",N("palette-grey-300")),H(b.Button,"inheritContainedHoverBg",N("palette-grey-A100")),H(b.Chip,"defaultBorder",N("palette-grey-400")),H(b.Chip,"defaultAvatarColor",N("palette-grey-700")),H(b.Chip,"defaultIconColor",N("palette-grey-700")),H(b.FilledInput,"bg","rgba(0, 0, 0, 0.06)"),H(b.FilledInput,"hoverBg","rgba(0, 0, 0, 0.09)"),H(b.FilledInput,"disabledBg","rgba(0, 0, 0, 0.12)"),H(b.LinearProgress,"primaryBg",M(et,i?u("palette-primary-main"):b.primary.main,.62)),H(b.LinearProgress,"secondaryBg",M(et,i?u("palette-secondary-main"):b.secondary.main,.62)),H(b.LinearProgress,"errorBg",M(et,i?u("palette-error-main"):b.error.main,.62)),H(b.LinearProgress,"infoBg",M(et,i?u("palette-info-main"):b.info.main,.62)),H(b.LinearProgress,"successBg",M(et,i?u("palette-success-main"):b.success.main,.62)),H(b.LinearProgress,"warningBg",M(et,i?u("palette-warning-light"):b.warning.main,.62)),H(b.Skeleton,"bg",T?M(pi,i?u("palette-text-primary"):b.text.primary,.11):`rgba(${N("palette-text-primaryChannel")} / 0.11)`),H(b.Slider,"primaryTrack",M(et,i?u("palette-primary-main"):b.primary.main,.62)),H(b.Slider,"secondaryTrack",M(et,i?u("palette-secondary-main"):b.secondary.main,.62)),H(b.Slider,"errorTrack",M(et,i?u("palette-error-main"):b.error.main,.62)),H(b.Slider,"infoTrack",M(et,i?u("palette-info-main"):b.info.main,.62)),H(b.Slider,"successTrack",M(et,iLine truncated
|
||||
0% {
|
||||
transform: scale(0);
|
||||
opacity: 0.1;
|
||||
@@ -52,7 +52,7 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
transform: scale(1);
|
||||
opacity: 0.3;
|
||||
}
|
||||
`,p_=vo`
|
||||
`,T_=Ro`
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
@@ -60,7 +60,7 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
`,c_=vo`
|
||||
`,b_=Ro`
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
@@ -72,23 +72,23 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
`,u_=D("span",{name:"MuiTouchRipple",slot:"Root"})({overflow:"hidden",pointerEvents:"none",position:"absolute",zIndex:0,top:0,right:0,bottom:0,left:0,borderRadius:"inherit"}),f_=D(WS,{name:"MuiTouchRipple",slot:"Ripple"})`
|
||||
`,v_=k("span",{name:"MuiTouchRipple",slot:"Root"})({overflow:"hidden",pointerEvents:"none",position:"absolute",zIndex:0,top:0,right:0,bottom:0,left:0,borderRadius:"inherit"}),x_=k(oC,{name:"MuiTouchRipple",slot:"Ripple"})`
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
|
||||
&.${Rr.rippleVisible} {
|
||||
&.${Or.rippleVisible} {
|
||||
opacity: 0.3;
|
||||
transform: scale(1);
|
||||
animation-name: ${l_};
|
||||
animation-duration: ${kT}ms;
|
||||
animation-name: ${g_};
|
||||
animation-duration: ${IT}ms;
|
||||
animation-timing-function: ${({theme:e})=>e.transitions.easing.easeInOut};
|
||||
}
|
||||
|
||||
&.${Rr.ripplePulsate} {
|
||||
&.${Or.ripplePulsate} {
|
||||
animation-duration: ${({theme:e})=>e.transitions.duration.shorter}ms;
|
||||
}
|
||||
|
||||
& .${Rr.child} {
|
||||
& .${Or.child} {
|
||||
opacity: 1;
|
||||
display: block;
|
||||
width: 100%;
|
||||
@@ -97,25 +97,25 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
background-color: currentColor;
|
||||
}
|
||||
|
||||
& .${Rr.childLeaving} {
|
||||
& .${Or.childLeaving} {
|
||||
opacity: 0;
|
||||
animation-name: ${p_};
|
||||
animation-duration: ${kT}ms;
|
||||
animation-name: ${T_};
|
||||
animation-duration: ${IT}ms;
|
||||
animation-timing-function: ${({theme:e})=>e.transitions.easing.easeInOut};
|
||||
}
|
||||
|
||||
& .${Rr.childPulsate} {
|
||||
& .${Or.childPulsate} {
|
||||
position: absolute;
|
||||
/* @noflip */
|
||||
left: 0px;
|
||||
top: 0;
|
||||
animation-name: ${c_};
|
||||
animation-name: ${b_};
|
||||
animation-duration: 2500ms;
|
||||
animation-timing-function: ${({theme:e})=>e.transitions.easing.easeInOut};
|
||||
animation-iteration-count: infinite;
|
||||
animation-delay: 200ms;
|
||||
}
|
||||
`,d_=Jt.forwardRef(function(t,o){let r=X({props:t,name:"MuiTouchRipple"}),{center:n=!1,classes:a={},className:i,...s}=r,[l,p]=Jt.useState([]),c=Jt.useRef(0),m=Jt.useRef(null);Jt.useEffect(()=>{m.current&&(m.current(),m.current=null)},[l]);let f=Jt.useRef(!1),u=Ko(),g=Jt.useRef(null),v=Jt.useRef(null),x=Jt.useCallback(T=>{let{pulsate:P,rippleX:S,rippleY:E,rippleSize:R,cb:w}=T;p(O=>[...O,(0,Rm.jsx)(f_,{classes:{ripple:L(a.ripple,Rr.ripple),rippleVisible:L(a.rippleVisible,Rr.rippleVisible),ripplePulsate:L(a.ripplePulsate,Rr.ripplePulsate),child:L(a.child,Rr.child),childLeaving:L(a.childLeaving,Rr.childLeaving),childPulsate:L(a.childPulsate,Rr.childPulsate)},timeout:kT,pulsate:P,rippleX:S,rippleY:E,rippleSize:R},c.current)]),c.current+=1,m.current=w},[a]),d=Jt.useCallback((T={},P={},S=()=>{})=>{let{pulsate:E=!1,center:R=n||P.pulsate,fakeElement:w=!1}=P;if(T?.type==="mousedown"&&f.current){f.current=!1;return}T?.type==="touchstart"&&(f.current=!0);let O=w?null:v.current,N=O?O.getBoundingClientRect():{width:0,height:0,left:0,top:0},b,M,A;if(R||T===void 0||T.clientX===0&&T.clientY===0||!T.clientX&&!T.touches)b=Math.round(N.width/2),M=Math.round(N.height/2);else{let{clientX:_,clientY:k}=T.touches&&T.touches.length>0?T.touches[0]:T;b=Math.round(_-N.left),M=Math.round(k-N.top)}if(R)A=Math.sqrt((2*N.width**2+N.height**2)/3),A%2===0&&(A+=1);else{let _=Math.max(Math.abs((O?O.clientWidth:0)-b),b)*2+2,k=Math.max(Math.abs((O?O.clientHeight:0)-M),M)*2+2;A=Math.sqrt(_**2+k**2)}T?.touches?g.current===null&&(g.current=()=>{x({pulsate:E,rippleX:b,rippleY:M,rippleSize:A,cb:S})},u.start(s_,()=>{g.current&&(g.current(),g.current=null)})):x({pulsate:E,rippleX:b,rippleY:M,rippleSize:A,cb:S})},[n,x,u]),y=Jt.useCallback(()=>{d({},{pulsate:!0})},[d]),h=Jt.useCallback((T,P)=>{if(u.clear(),T?.type==="touchend"&&g.current){g.current(),g.current=null,u.start(0,()=>{h(T,P)});return}g.current=null,p(S=>S.length>0?S.slice(1):S),m.current=P},[u]);return Jt.useImperativeHandle(o,()=>({pulsate:y,start:d,stop:h}),[y,d,h]),(0,Rm.jsx)(u_,{className:L(Rr.root,a.root,i),ref:v,...s,children:(0,Rm.jsx)(wT,{component:null,exit:!0,children:l})})}),XS=d_;function QS(e){return q("MuiButtonBase",e)}var m_=G("MuiButtonBase",["root","disabled","focusVisible"]),ZS=m_;var Om=C(U(),1),y_=e=>{let{disabled:t,focusVisible:o,focusVisibleClassName:r,classes:n}=e,i=Y({root:["root",t&&"disabled",o&&"focusVisible"]},QS,n);return o&&r&&(i.root+=` ${r}`),i},h_=D("button",{name:"MuiButtonBase",slot:"Root"})({display:"inline-flex",alignItems:"center",justifyContent:"center",position:"relative",boxSizing:"border-box",WebkitTapHighlightColor:"transparent",backgroundColor:"transparent",outline:0,border:0,margin:0,borderRadius:0,padding:0,cursor:"pointer",userSelect:"none",verticalAlign:"middle",MozAppearance:"none",WebkitAppearance:"none",textDecoration:"none",color:"inherit","&::-moz-focus-inner":{borderStyle:"none"},[`&.${ZS.disabled}`]:{pointerEvents:"none",cursor:"default"},"@media print":{colorAdjust:"exact"}}),g_=Kn.forwardRef(function(t,o){let r=X({props:t,name:"MuiButtonBase"}),{action:n,centerRipple:a=!1,children:i,className:s,component:l="button",disabled:p=!1,disableRipple:c=!1,disableTouchRipple:m=!1,focusRipple:f=!1,focusVisibleClassName:u,LinkComponent:g="a",onBlur:v,onClick:x,onContextMenu:d,onDragLeave:y,onFocus:h,onFocusVisible:T,onKeyDown:P,onKeyUp:S,onMouseDown:E,onMouseLeave:R,onMouseUp:w,onTouchEnd:O,onTouchMove:N,onTouchStart:b,tabIndex:M=0,TouchRippleProps:A,touchRippleRef:_,type:k,...W}=r,re=Kn.useRef(null),F=Cm(),me=St(F.ref,_),[ie,ue]=Kn.useState(!1);p&&ie&&ue(!1),Kn.useImperativeHandle(n,()=>({focusVisible:()=>{ue(!0),re.current.focus()}}),[]);let ne=F.shouldMount&&!c&&!p;Kn.useEffect(()=>{ie&&f&&!c&&F.pulsate()},[c,f,ie,F]);let Ee=Ca(F,"start",E,m),le=Ca(F,"stop",d,m),oe=Ca(F,"stop",y,m),ye=Ca(F,"stop",w,m),ge=Ca(F,"stop",pe=>{ie&&pe.preventDefault(),R&&R(pe)},m),Te=Ca(F,"start",b,m),se=Ca(F,"stop",O,m),de=Ca(F,"stop",N,m),be=Ca(F,"stop",pe=>{vn(pe.target)||ue(!1),v&&v(pe)},!1),$=ii(pe=>{re.current||(re.current=pe.currentTarget),vn(pe.target)&&(ue(!0),T&&T(pe)),h&&h(pe)}),z=()=>{let pe=re.current;return pe?pe.tagName==="BUTTON"?!1:!(pe.tagName==="A"&&pe.href):l&&l!=="button"},xe=ii(pe=>{f&&!pe.repeat&&ie&&pe.key===" "&&F.stop(pe,()=>{F.start(pe)}),pe.target===pe.currentTarget&&z()&&pe.key===" "&&pe.preventDefault(),P&&P(pe),pe.target===pe.currentTarget&&z()&&pe.key==="Enter"&&!p&&(pe.preventDefault(),x&&x(pe))}),Oe=ii(pe=>{f&&pe.key===" "&&ie&&!pe.defaultPrevented&&F.stop(pe,()=>{F.pulsate(pe)}),S&&S(pe),x&&pe.target===pe.currentTarget&&z()&&pe.key===" "&&!pe.defaultPrevented&&!p&&x(pe)}),Pe=l;Pe==="button"&&(W.href||W.to)&&(Pe=g);let ke={};if(Pe==="button"){let pe=!!W.formAction;ke.type=k===void 0&&!pe?"button":k,ke.disabled=p}else!W.href&&!W.to&&(ke.role="button"),p&&(ke["aria-disabled"]=p);let qe=St(o,re),$e={...r,centerRipple:a,component:l,disabled:p,disableRipple:c,disableTouchRipple:m,focusRipple:f,tabIndex:M,focusVisible:ie},Ne=y_($e);return
Line truncated
|
||||
`,P_=ao.forwardRef(function(t,o){let r=Q({props:t,name:"MuiTouchRipple"}),{center:n=!1,classes:a={},className:i,...s}=r,[l,p]=ao.useState([]),c=ao.useRef(0),d=ao.useRef(null);ao.useEffect(()=>{d.current&&(d.current(),d.current=null)},[l]);let f=ao.useRef(!1),u=Zo(),g=ao.useRef(null),x=ao.useRef(null),v=ao.useCallback(T=>{let{pulsate:P,rippleX:S,rippleY:E,rippleSize:R,cb:w}=T;p(O=>[...O,(0,_m.jsx)(x_,{classes:{ripple:L(a.ripple,Or.ripple),rippleVisible:L(a.rippleVisible,Or.rippleVisible),ripplePulsate:L(a.ripplePulsate,Or.ripplePulsate),child:L(a.child,Or.child),childLeaving:L(a.childLeaving,Or.childLeaving),childPulsate:L(a.childPulsate,Or.childPulsate)},timeout:IT,pulsate:P,rippleX:S,rippleY:E,rippleSize:R},c.current)]),c.current+=1,d.current=w},[a]),m=ao.useCallback((T={},P={},S=()=>{})=>{let{pulsate:E=!1,center:R=n||P.pulsate,fakeElement:w=!1}=P;if(T?.type==="mousedown"&&f.current){f.current=!1;return}T?.type==="touchstart"&&(f.current=!0);let O=w?null:x.current,A=O?O.getBoundingClientRect():{width:0,height:0,left:0,top:0},b,N,M;if(R||T===void 0||T.clientX===0&&T.clientY===0||!T.clientX&&!T.touches)b=Math.round(A.width/2),N=Math.round(A.height/2);else{let{clientX:_,clientY:D}=T.touches&&T.touches.length>0?T.touches[0]:T;b=Math.round(_-A.left),N=Math.round(D-A.top)}if(R)M=Math.sqrt((2*A.width**2+A.height**2)/3),M%2===0&&(M+=1);else{let _=Math.max(Math.abs((O?O.clientWidth:0)-b),b)*2+2,D=Math.max(Math.abs((O?O.clientHeight:0)-N),N)*2+2;M=Math.sqrt(_**2+D**2)}T?.touches?g.current===null&&(g.current=()=>{v({pulsate:E,rippleX:b,rippleY:N,rippleSize:M,cb:S})},u.start(h_,()=>{g.current&&(g.current(),g.current=null)})):v({pulsate:E,rippleX:b,rippleY:N,rippleSize:M,cb:S})},[n,v,u]),y=ao.useCallback(()=>{m({},{pulsate:!0})},[m]),h=ao.useCallback((T,P)=>{if(u.clear(),T?.type==="touchend"&&g.current){g.current(),g.current=null,u.start(0,()=>{h(T,P)});return}g.current=null,p(S=>S.length>0?S.slice(1):S),d.current=P},[u]);return ao.useImperativeHandle(o,()=>({pulsate:y,start:m,stop:h}),[y,m,h]),(0,_m.jsx)(v_,{className:L(Or.root,a.root,i),ref:x,...s,children:(0,_m.jsx)(zT,{component:null,exit:!0,children:l})})}),rC=P_;function nC(e){return G("MuiButtonBase",e)}var S_=Y("MuiButtonBase",["root","disabled","focusVisible"]),aC=S_;var zm=C(z(),1),C_=e=>{let{disabled:t,focusVisible:o,focusVisibleClassName:r,classes:n}=e,i=W({root:["root",t&&"disabled",o&&"focusVisible"]},nC,n);return o&&r&&(i.root+=` ${r}`),i},E_=k("button",{name:"MuiButtonBase",slot:"Root"})({display:"inline-flex",alignItems:"center",justifyContent:"center",position:"relative",boxSizing:"border-box",WebkitTapHighlightColor:"transparent",backgroundColor:"transparent",outline:0,border:0,margin:0,borderRadius:0,padding:0,cursor:"pointer",userSelect:"none",verticalAlign:"middle",MozAppearance:"none",WebkitAppearance:"none",textDecoration:"none",color:"inherit","&::-moz-focus-inner":{borderStyle:"none"},[`&.${aC.disabled}`]:{pointerEvents:"none",cursor:"default"},"@media print":{colorAdjust:"exact"}}),R_=Qn.forwardRef(function(t,o){let r=Q({props:t,name:"MuiButtonBase"}),{action:n,centerRipple:a=!1,children:i,className:s,component:l="button",disabled:p=!1,disableRipple:c=!1,disableTouchRipple:d=!1,focusRipple:f=!1,focusVisibleClassName:u,LinkComponent:g="a",onBlur:x,onClick:v,onContextMenu:m,onDragLeave:y,onFocus:h,onFocusVisible:T,onKeyDown:P,onKeyUp:S,onMouseDown:E,onMouseLeave:R,onMouseUp:w,onTouchEnd:O,onTouchMove:A,onTouchStart:b,tabIndex:N=0,TouchRippleProps:M,touchRippleRef:_,type:D,...K}=r,ee=Qn.useRef(null),q=km(),ye=Et(q.ref,_),[se,ce]=Qn.useState(!1);p&&se&&ce(!1),Qn.useImperativeHandle(n,()=>({focusVisible:()=>{ce(!0),ee.current.focus()}}),[]);let oe=q.shouldMount&&!c&&!p;Qn.useEffect(()=>{se&&f&&!c&&q.pulsate()},[c,f,se,q]);let Ce=wa(q,"start",E,d),pe=wa(q,"stop",m,d),re=wa(q,"stop",y,d),Te=wa(q,"stop",w,d),he=wa(q,"stop",ae=>{se&&ae.preventDefault(),R&&R(ae)},d),Ee=wa(q,"start",b,d),le=wa(q,"stop",O,d),fe=wa(q,"stop",A,d),ge=wa(q,"stop",ae=>{xn(ae.target)||ce(!1),x&&x(ae)},!1),$=ui(ae=>{ee.current||(ee.current=ae.currentTarget),xn(ae.target)&&(ce(!0),T&&T(ae)),h&&h(ae)}),U=()=>{let ae=ee.current;return ae?ae.tagName==="BUTTON"?!1:!(ae.tagName==="A"&&ae.href):l&&l!=="button"},Pe=ui(ae=>{f&&!ae.repeat&&se&&ae.key===" "&&q.stop(ae,()=>{q.start(ae)}),ae.target===ae.currentTarget&&U()&&ae.key===" "&&ae.preventDefault(),P&&P(ae),ae.target===ae.currentTarget&&U()&&ae.key==="Enter"&&!p&&(ae.preventDefault(),v&&v(ae))}),Me=ui(ae=>{f&&ae.key===" "&&se&&!ae.defaultPrevented&&q.stop(ae,()=>{q.pulsate(ae)}),S&&S(ae),v&&ae.target===ae.currentTarget&&U()&&ae.key===" "&&!ae.defaultPrevented&&!p&&v(ae)}),Se=l;Se==="button"&&(K.href||K.to)&&(Se=g);let Oe={};if(Se==="button"){let ae=!!K.formAction;Oe.type=D===void 0&&!ae?"button":D,Oe.disabled=p}else!K.href&&!K.to&&(Oe.role="button"),p&&(Oe["aria-disabled"]=p);let Ve=Et(o,ee),Ze={...r,centerRipple:a,component:l,disabled:p,disableRipple:c,disableTouchRipple:d,focusRipple:f,tabIndex:N,focusVisible:se},Fe=C_(Ze);return
Line truncated
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
@@ -123,7 +123,7 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
`,jT=vo`
|
||||
`,VT=Ro`
|
||||
0% {
|
||||
stroke-dasharray: 1px, 200px;
|
||||
stroke-dashoffset: 0;
|
||||
@@ -138,13 +138,13 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
stroke-dasharray: 1px, 200px;
|
||||
stroke-dashoffset: -126px;
|
||||
}
|
||||
`,O_=typeof zT!="string"?ir`
|
||||
animation: ${zT} 1.4s linear infinite;
|
||||
`:null,w_=typeof jT!="string"?ir`
|
||||
animation: ${jT} 1.4s ease-in-out infinite;
|
||||
`:null,N_=e=>{let{classes:t,variant:o,color:r,disableShrink:n}=e,a={root:["root",o,`color${j(r)}`],svg:["svg"],track:["track"],circle:["circle",`circle${j(o)}`,n&&"circleDisableShrink"]};return Y(a,tC,t)},M_=D("span",{name:"MuiCircularProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[o.variant],t[`color${j(o.color)}`]]}})(Z(({theme:e})=>({display:"inline-block",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("transform")}},{props:{variant:"indeterminate"},style:O_||{animation:`${zT} 1.4s linear infinite`}},...Object.entries(e.palette).filter(Be()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}}))]}))),A_=D("svg",{name:"MuiCircularProgress",slot:"Svg"})({display:"block"}),D_=D("circle",{name:"MuiCircularProgress",slot:"Circle",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.circle,t[`circle${j(o.variant)}`],o.disableShrink&&t.circleDisableShrink]}})(Z(({theme:e})=>({stroke:"currentColor",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("stroke-dashoffset")}},{props:{variant:"indeterminate"},style:{strokeDasharray:"80px, 200px",strokeDashoffset:0}},{props:({ownerState:t})=>t.variant==="indeterminate"&&!t.disableShrink,style:w_||{animation:`${jT} 1.4s ease-in-out infinite`}}]}))),k_=D("circle",{name:"MuiCircularProgress",slot:"Track"})(Z(({theme:e})=>({stroke:"currentColor",opacity:(e.vars||e).palette.action.activatedOpacity}))),__=oC.forwardRef(function(t,o){let r=X({props:t,name:"MuiCircularProgress"}),{className:n,color:a="primary",disableShrink:i=!1,enableTrackSlot:s=!1,size:l=40,style:p,thickness:c=3.6,value:m=0,variant:f="indeterminate",...u}=r,g={...r,color:a,disableShrink:i,size:l,thickness:c,value:m,variant:f,enableTrackSlot:s},v=N_(g),x={},d={},y={};if(f==="determinate"){let h=2*Math.PI*((xn-c)/2);x.strokeDasharray=h.toFixed(3),y["aria-valuenow"]=Math.round(m),x.strokeDashoffset=`${((100-m)/100*h).toFixed(3)}px`,d.transform="rotate(-90deg)"}return(0,Ql.jsx)(M_,{className:L(v.root,n),style:{width:l,height:l,...d,...p},ownerState:g,ref:o,role:"progressbar",...y,...u,children:(0,Ql.jsxs)(A_,{className:v.svg,ownerState:g,viewBox:`${xn/2} ${xn/2} ${xn} ${xn}`,children:[s?(0,Ql.jsx)(k_,{className:v.track,ownerState:g,cx:xn,cy:xn,r:(xn-c)/2,fill:"none",strokeWidth:c,"aria-hidden":"true"}):null,(0,Ql.jsx)(D_,{className:v.circle,style:x,ownerState:g,cx:xn,cy:xn,r:(xn-c)/2,fill:"none",strokeWidth:c})]})})}),fu=__;function rC(e){return q("MuiIconButton",e)}var z_=G("MuiIconButton",["root","disabled","colorInherit","colorPrimary","colorSecondary","colorError","colorInfo","colorSuccess","colorWarning","edgeStart","edgeEnd","sizeSmall","sizeMedium","sizeLarge","loading","loadingIndicator","loadingWrapper"]),BT=z_;var Zl=C(U(),1),j_=e=>{let{classes:t,disabled:o,color:r,edge:n,size:a,loading:i}=e,s={root:["root",i&&"loading",o&&"disabled",r!=="default"&&`color${j(r)}`,n&&`edge${j(n)}`,`size${j(a)}`],loadingIndicator:["loadingIndicator"],loadingWrapper:["loadingWrapper"]};return Y(s,rC,t)},B_=D(pr,{name:"MuiIconButton",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,o.loading&&t.loading,o.color!=="default"&&t[`color${j(o.color)}`],o.edge&&t[`edge${j(o.edge)}`],t[`size${j(o.size)}`]]}})(Z(({theme:e})=>({textAlign:"center",flex:"0 0 auto",fontSize:e.typography.pxToRem(24),padding:8,borderRadius:"50%",color:(e.vars||e).palette.action.active,transition:e.transitions.create("background-color",{duration:e.transitions.duration.shortest}),variants:[{props:t=>!t.disableRipple,style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette.action.active,(e.vars||e).palette.action.hoverOpacity),"&:hover":{backgroundColor:"var(--IconButton-hoverBg)","@media (hover: none)":{backgroundColor:"transparent"}}}},{props:{edge:"start"},style:{marginLeft:-12}},{props:{edge:"start",size:"small"},style:{marginLeft:-3}},{props:{edge:"end"},style:{marginRight:-12}},{props:{edge:"end",size:"small"},style:{marginRight:-3}}]})),Z(({theme:e})=>({variants:[{props:{color:"inherit"},style:{color:"inherit"}},...Object.entries(e.palette).filter(Be()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}})),...Object.entries(e.palette).filter(Be()).map(([t])=>({props:{color:t},style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette[t].main,(e.vars||e).palette.action.hoverOpacity)}})),{props:{size:"small"},style:{padding:5,fontSize:e.typography.pxToRem(18)}},{props:{size:"large"},style:{padding:12,fontSize:e.typography.pxToRem(28)}}],[`&.${BT.disabled}`]:{backgroundColor:"transparent",color:(e.vars||e).palette.action.disabled},[`&.${BT.loading}`]:{color:"transparent"}}))),U_=D("span",{name:"MuiIconButton",slot:"LoadingIndicator"})(({theme:e})=>({display:"none",position:"absolute",visibility:"visible",top:"50%",left:"50%",transform:"translate(-50%, -50%)",color:(e.vars||e).palette.action.disabled,variants:[{props:{loading:!0},style:{display:"flex"}}]})),L_=Mm.forwardRef(function(t,o){
Line truncated
|
||||
`&&(T.value+=" ");let E=S.boxSizing,R=Im(S.paddingBottom)+Im(S.paddingTop),w=Im(S.borderBottomWidth)+Im(S.borderTopWidth),O=T.scrollHeight;T.value="x";let N=T.scrollHeight,b=O;a&&(b=Math.max(Number(a)*N,b)),n&&(b=Math.min(Number(n)*N,b)),b=Math.max(b,N);let M=b+(E==="border-box"?R+w:0),A=Math.abs(b-O)<=1;return{outerHeightStyle:M,overflowing:A}},[n,a,t.placeholder]),v=Er(()=>{let h=c.current,T=g();if(!h||!T||QC(T))return!1;let P=T.outerHeightStyle;return f.current!=null&&f.current!==P}),x=Mr.useCallback(()=>{let h=c.current,T=g();if(!h||!T||QC(T))return;let P=T.outerHeightStyle;f.current!==P&&(f.current=P,h.style.height=`${P}px`),h.style.overflow=T.overflowing?"hidden":""},[g]),d=Mr.useRef(-1);return Gt(()=>{let h=Il(x),T=c?.current;if(!T)return;let P=Kr(T);P.addEventListener("resize",h);let S;return typeof ResizeObserver<"u"&&(S=new ResizeObserver(()=>{v()&&(S.unobserve(T),cancelAnimationFrame(d.current),x(),d.current=requestAnimationFrame(()=>{S.observe(T)}))}),S.observe(T)),()=>{h.clear(),cancelAnimationFrame(d.current),P.removeEventListener("resize",h),S&&S.disconnect()}},[g,x,v]),Gt(()=>{x()}),(0,Pu.jsxs)(Mr.Fragment,{children:[(0,Pu.jsx)("textarea",{value:s,onChange:h=>{p||x();let T=h.target,P=T.value.length,S=T.value.endsWith(`
|
||||
`),E=T.selectionStart===P;S&&E&&T.setSelectionRange(P,P),r&&r(h)},ref:m,rows:a,style:i,...l}),(0,Pu.jsx)("textarea",{"aria-hidden":!0,className:t.className,readOnly:!0,ref:u,tabIndex:-1,style:{...Yz.shadow,...i,paddingTop:0,paddingBottom:0}})]})}),JT=Wz;function Xo({props:e,states:t,muiFormControl:o}){return t.reduce((r,n)=>(r[n]=e[n],o&&typeof e[n]>"u"&&(r[n]=o[n]),r),{})}var ZC=C(I(),1),Xz=ZC.createContext(void 0),np=Xz;var JC=C(I(),1);function uo(){return JC.useContext(np)}function Hm(e){let t=e.activeElement;for(;t?.shadowRoot?.activeElement!=null;)t=t.shadowRoot.activeElement;return t}var Na=Hm;function eE(e){return e!=null&&!(Array.isArray(e)&&e.length===0)}function Os(e,t=!1){return e&&(eE(e.value)&&e.value!==""||t&&eE(e.defaultValue)&&e.defaultValue!=="")}function tE(e){return e.startAdornment}function oE(e){return q("MuiInputBase",e)}var Qz=G("MuiInputBase",["root","formControl","focused","disabled","adornedStart","adornedEnd","error","sizeSmall","multiline","colorSecondary","fullWidth","hiddenLabel","readOnly","input","inputSizeSmall","inputMultiline","inputTypeSearch","inputAdornedStart","inputAdornedEnd","inputHiddenLabel"]),En=Qz;var ws=C(U(),1),rE,eb="mui-auto-fill",$m="mui-auto-fill-cancel",Ns=(e,t)=>{let{ownerState:o}=e;return[t.root,o.formControl&&t.formControl,o.startAdornment&&t.adornedStart,o.endAdornment&&t.adornedEnd,o.error&&t.error,o.size==="small"&&t.sizeSmall,o.multiline&&t.multiline,o.color&&t[`color${j(o.color)}`],o.fullWidth&&t.fullWidth,o.hiddenLabel&&t.hiddenLabel]},Ms=(e,t)=>{let{ownerState:o}=e;return[t.input,o.size==="small"&&t.inputSizeSmall,o.multiline&&t.inputMultiline,o.type==="search"&&t.inputTypeSearch,o.startAdornment&&t.inputAdornedStart,o.endAdornment&&t.inputAdornedEnd,o.hiddenLabel&&t.inputHiddenLabel]},Zz=e=>{let{classes:t,color:o,disabled:r,error:n,endAdornment:a,focused:i,formControl:s,fullWidth:l,hiddenLabel:p,multiline:c,readOnly:m,size:f,startAdornment:u,type:g}=e,v={root:["root",`color${j(o)}`,r&&"disabled",n&&"error",l&&"fullWidth",i&&"focused",s&&"formControl",f&&f!=="medium"&&`size${j(f)}`,c&&"multiline",u&&"adornedStart",a&&"adornedEnd",p&&"hiddenLabel",m&&"readOnly"],input:["input",r&&"disabled",g==="search"&&"inputTypeSearch",c&&"inputMultiline",f==="small"&&"inputSizeSmall",p&&"inputHiddenLabel",u&&"inputAdornedStart",a&&"inputAdornedEnd",m&&"readOnly"]};return Y(v,oE,t)},As=D("div",{name:"MuiInputBase",slot:"Root",overridesResolver:Ns})(Z(({theme:e})=>({...e.typography.body1,color:(e.vars||e).palette.text.primary,lineHeight:"1.4375em",boxSizing:"border-box",position:"relative",cursor:"text",display:"inline-flex",alignItems:"center",[`&.${En.disabled}`]:{color:(e.vars||e).palette.text.disabled,cursor:"default"},variants:[{props:({ownerState:t})=>t.multiline,style:{padding:"4px 0 5px"}},{props:({ownerState:t,size:o})=>t.multiline&&o==="small",style:{paddingTop:1}},{props:({ownerState:t})=>t.fullWidth,style:{width:"100%"}}]}))),Ds=D("input",{name:"MuiInputBase",slot:"Input",overridesResolver:Ms})(Z(({theme:e})=>{let t=e.palette.mode==="light",o={color:"currentColor",...e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5},transition:e.transitions.create("opacity",{duration:e.transitions.duration.shorter})},r={opacity:"0 !important"},n=e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5};return{font:"inherit",letterSpacing:"inherit",color:"currentColor",padding:"4px 0 5px",border:0,boxSizing:"content-box",background:"none",height:"1.4375em",margin:0,WebkitTapHighlightColor:"transparent",display:"block",minWidth:0,width:"100%","&::-webkit-input-placeholder":o,"&::-moz-placeholder":o,"&::-ms-input-placeholder":o,"&:focus":{outline:0},"&:invalid":{boxShadow:"none"},"&::-webkit-search-decoration":{WebkitAppearance:"none"},[`label[data-shrink=false] + .${En.formControl} &`]:{"&::-webkit-input-placeholder":r,"&::-moz-placeholder":r,"&::-ms-input-placeholder":r,"&:focus::-webkit-input-placeholder":n,"&:focus::-moz-placeholder":n,"&:focus::-ms-input-placeholder":n},[`&.${En.disabled}`]:{opacity:1,WebkitTextFillColor:(e.vars||e).palette.text.disabled},variants:[{props:({ownerState:a})=>!a.disableInjectingGlobalStyles,style:{animationName:$m,animationDuration:"10ms","&:-webkit-autofill":{animationDuration:"5000s",animationName:eb}}},{props:{size:"small"},style:{paddingTop:1}},{props:({ownerState:a})=>a.multiline,style:{height:"auto",resize:"none",padding:0,paddingTop:0}},{props:{type:"search"},style:{MozAppearance:"textfield"}}]}})),nE=Jc({[`@keyframes ${eb}`]:{from:{animationName:eb}},[`@keyframes ${$m}`]:{from:{animationName:$m}}}),Jz=Uo.forwardRef(function(t,o){let r=X({props:t,name:"MuiInputBase"}),{"aria-describedby":n,autoComplete:a,autoFocus:i,className:s,color:l,components:p={},componentsProps:c={},defaultValue:m,disabled:f,disableInjectingGlobalStyles:u,endAdornment:g,error:v,fullWidth:x=!1,id:d,inputComponent:y="input",inputProps:h={},inputRef:T,margin:P,maxRows:S,minRows:E,multiline:R=!1,name:w,onBlur:O,onChange:N,onClick
Line truncated
|
||||
`,j_=typeof HT!="string"?pr`
|
||||
animation: ${HT} 1.4s linear infinite;
|
||||
`:null,B_=typeof VT!="string"?pr`
|
||||
animation: ${VT} 1.4s ease-in-out infinite;
|
||||
`:null,U_=e=>{let{classes:t,variant:o,color:r,disableShrink:n}=e,a={root:["root",o,`color${B(r)}`],svg:["svg"],track:["track"],circle:["circle",`circle${B(o)}`,n&&"circleDisableShrink"]};return W(a,lC,t)},L_=k("span",{name:"MuiCircularProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[o.variant],t[`color${B(o.color)}`]]}})(J(({theme:e})=>({display:"inline-block",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("transform")}},{props:{variant:"indeterminate"},style:j_||{animation:`${HT} 1.4s linear infinite`}},...Object.entries(e.palette).filter(Ue()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}}))]}))),I_=k("svg",{name:"MuiCircularProgress",slot:"Svg"})({display:"block"}),$_=k("circle",{name:"MuiCircularProgress",slot:"Circle",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.circle,t[`circle${B(o.variant)}`],o.disableShrink&&t.circleDisableShrink]}})(J(({theme:e})=>({stroke:"currentColor",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("stroke-dashoffset")}},{props:{variant:"indeterminate"},style:{strokeDasharray:"80px, 200px",strokeDashoffset:0}},{props:({ownerState:t})=>t.variant==="indeterminate"&&!t.disableShrink,style:B_||{animation:`${VT} 1.4s ease-in-out infinite`}}]}))),H_=k("circle",{name:"MuiCircularProgress",slot:"Track"})(J(({theme:e})=>({stroke:"currentColor",opacity:(e.vars||e).palette.action.activatedOpacity}))),V_=pC.forwardRef(function(t,o){let r=Q({props:t,name:"MuiCircularProgress"}),{className:n,color:a="primary",disableShrink:i=!1,enableTrackSlot:s=!1,size:l=40,style:p,thickness:c=3.6,value:d=0,variant:f="indeterminate",...u}=r,g={...r,color:a,disableShrink:i,size:l,thickness:c,value:d,variant:f,enableTrackSlot:s},x=U_(g),v={},m={},y={};if(f==="determinate"){let h=2*Math.PI*((Pn-c)/2);v.strokeDasharray=h.toFixed(3),y["aria-valuenow"]=Math.round(d),v.strokeDashoffset=`${((100-d)/100*h).toFixed(3)}px`,m.transform="rotate(-90deg)"}return(0,ap.jsx)(L_,{className:L(x.root,n),style:{width:l,height:l,...m,...p},ownerState:g,ref:o,role:"progressbar",...y,...u,children:(0,ap.jsxs)(I_,{className:x.svg,ownerState:g,viewBox:`${Pn/2} ${Pn/2} ${Pn} ${Pn}`,children:[s?(0,ap.jsx)(H_,{className:x.track,ownerState:g,cx:Pn,cy:Pn,r:(Pn-c)/2,fill:"none",strokeWidth:c,"aria-hidden":"true"}):null,(0,ap.jsx)($_,{className:x.circle,style:v,ownerState:g,cx:Pn,cy:Pn,r:(Pn-c)/2,fill:"none",strokeWidth:c})]})})}),yi=V_;function cC(e){return G("MuiIconButton",e)}var F_=Y("MuiIconButton",["root","disabled","colorInherit","colorPrimary","colorSecondary","colorError","colorInfo","colorSuccess","colorWarning","edgeStart","edgeEnd","sizeSmall","sizeMedium","sizeLarge","loading","loadingIndicator","loadingWrapper"]),FT=F_;var ip=C(z(),1),q_=e=>{let{classes:t,disabled:o,color:r,edge:n,size:a,loading:i}=e,s={root:["root",i&&"loading",o&&"disabled",r!=="default"&&`color${B(r)}`,n&&`edge${B(n)}`,`size${B(a)}`],loadingIndicator:["loadingIndicator"],loadingWrapper:["loadingWrapper"]};return W(s,cC,t)},G_=k(fr,{name:"MuiIconButton",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,o.loading&&t.loading,o.color!=="default"&&t[`color${B(o.color)}`],o.edge&&t[`edge${B(o.edge)}`],t[`size${B(o.size)}`]]}})(J(({theme:e})=>({textAlign:"center",flex:"0 0 auto",fontSize:e.typography.pxToRem(24),padding:8,borderRadius:"50%",color:(e.vars||e).palette.action.active,transition:e.transitions.create("background-color",{duration:e.transitions.duration.shortest}),variants:[{props:t=>!t.disableRipple,style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette.action.active,(e.vars||e).palette.action.hoverOpacity),"&:hover":{backgroundColor:"var(--IconButton-hoverBg)","@media (hover: none)":{backgroundColor:"transparent"}}}},{props:{edge:"start"},style:{marginLeft:-12}},{props:{edge:"start",size:"small"},style:{marginLeft:-3}},{props:{edge:"end"},style:{marginRight:-12}},{props:{edge:"end",size:"small"},style:{marginRight:-3}}]})),J(({theme:e})=>({variants:[{props:{color:"inherit"},style:{color:"inherit"}},...Object.entries(e.palette).filter(Ue()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}})),...Object.entries(e.palette).filter(Ue()).map(([t])=>({props:{color:t},style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette[t].main,(e.vars||e).palette.action.hoverOpacity)}})),{props:{size:"small"},style:{padding:5,fontSize:e.typography.pxToRem(18)}},{props:{size:"large"},style:{padding:12,fontSize:e.typography.pxToRem(28)}}],[`&.${FT.disabled}`]:{backgroundColor:"transparent",color:(e.vars||e).palette.action.disabled},[`&.${FT.loading}`]:{color:"transparent"}}))),Y_=k("span",{name:"MuiIconButton",slot:"LoadingIndicator"})(({theme:e})=>({display:"none",position:"absolute",visibility:"visible",top:"50%",left:"50%",transform:"translate(-50%, -50%)",color:(e.vars||e).palette.action.disabled,variants:[{props:{loading:!0},style:{display:"flex"}}]})),W_=Um.forwardRef(function(t,o){
Line truncated
|
||||
`&&(T.value+=" ");let E=S.boxSizing,R=Wm(S.paddingBottom)+Wm(S.paddingTop),w=Wm(S.borderBottomWidth)+Wm(S.borderTopWidth),O=T.scrollHeight;T.value="x";let A=T.scrollHeight,b=O;a&&(b=Math.max(Number(a)*A,b)),n&&(b=Math.min(Number(n)*A,b)),b=Math.max(b,A);let N=b+(E==="border-box"?R+w:0),M=Math.abs(b-O)<=1;return{outerHeightStyle:N,overflowing:M}},[n,a,t.placeholder]),x=Rr(()=>{let h=c.current,T=g();if(!h||!T||nE(T))return!1;let P=T.outerHeightStyle;return f.current!=null&&f.current!==P}),v=Mr.useCallback(()=>{let h=c.current,T=g();if(!h||!T||nE(T))return;let P=T.outerHeightStyle;f.current!==P&&(f.current=P,h.style.height=`${P}px`),h.style.overflow=T.overflowing?"hidden":""},[g]),m=Mr.useRef(-1);return Xt(()=>{let h=Wl(v),T=c?.current;if(!T)return;let P=Kr(T);P.addEventListener("resize",h);let S;return typeof ResizeObserver<"u"&&(S=new ResizeObserver(()=>{x()&&(S.unobserve(T),cancelAnimationFrame(m.current),v(),m.current=requestAnimationFrame(()=>{S.observe(T)}))}),S.observe(T)),()=>{h.clear(),cancelAnimationFrame(m.current),P.removeEventListener("resize",h),S&&S.disconnect()}},[g,v,x]),Xt(()=>{v()}),(0,Mu.jsxs)(Mr.Fragment,{children:[(0,Mu.jsx)("textarea",{value:s,onChange:h=>{p||v();let T=h.target,P=T.value.length,S=T.value.endsWith(`
|
||||
`),E=T.selectionStart===P;S&&E&&T.setSelectionRange(P,P),r&&r(h)},ref:d,rows:a,style:i,...l}),(0,Mu.jsx)("textarea",{"aria-hidden":!0,className:t.className,readOnly:!0,ref:u,tabIndex:-1,style:{...o6.shadow,...i,paddingTop:0,paddingBottom:0}})]})}),ib=n6;function tr({props:e,states:t,muiFormControl:o}){return t.reduce((r,n)=>(r[n]=e[n],o&&typeof e[n]>"u"&&(r[n]=o[n]),r),{})}var aE=C(I(),1),a6=aE.createContext(void 0),fp=a6;var iE=C(I(),1);function go(){return iE.useContext(fp)}function Km(e){let t=e.activeElement;for(;t?.shadowRoot?.activeElement!=null;)t=t.shadowRoot.activeElement;return t}var Da=Km;function sE(e){return e!=null&&!(Array.isArray(e)&&e.length===0)}function _s(e,t=!1){return e&&(sE(e.value)&&e.value!==""||t&&sE(e.defaultValue)&&e.defaultValue!=="")}function lE(e){return e.startAdornment}function pE(e){return G("MuiInputBase",e)}var i6=Y("MuiInputBase",["root","formControl","focused","disabled","adornedStart","adornedEnd","error","sizeSmall","multiline","colorSecondary","fullWidth","hiddenLabel","readOnly","input","inputSizeSmall","inputMultiline","inputTypeSearch","inputAdornedStart","inputAdornedEnd","inputHiddenLabel"]),Rn=i6;var zs=C(z(),1),cE,sb="mui-auto-fill",Xm="mui-auto-fill-cancel",js=(e,t)=>{let{ownerState:o}=e;return[t.root,o.formControl&&t.formControl,o.startAdornment&&t.adornedStart,o.endAdornment&&t.adornedEnd,o.error&&t.error,o.size==="small"&&t.sizeSmall,o.multiline&&t.multiline,o.color&&t[`color${B(o.color)}`],o.fullWidth&&t.fullWidth,o.hiddenLabel&&t.hiddenLabel]},Bs=(e,t)=>{let{ownerState:o}=e;return[t.input,o.size==="small"&&t.inputSizeSmall,o.multiline&&t.inputMultiline,o.type==="search"&&t.inputTypeSearch,o.startAdornment&&t.inputAdornedStart,o.endAdornment&&t.inputAdornedEnd,o.hiddenLabel&&t.inputHiddenLabel]},s6=e=>{let{classes:t,color:o,disabled:r,error:n,endAdornment:a,focused:i,formControl:s,fullWidth:l,hiddenLabel:p,multiline:c,readOnly:d,size:f,startAdornment:u,type:g}=e,x={root:["root",`color${B(o)}`,r&&"disabled",n&&"error",l&&"fullWidth",i&&"focused",s&&"formControl",f&&f!=="medium"&&`size${B(f)}`,c&&"multiline",u&&"adornedStart",a&&"adornedEnd",p&&"hiddenLabel",d&&"readOnly"],input:["input",r&&"disabled",g==="search"&&"inputTypeSearch",c&&"inputMultiline",f==="small"&&"inputSizeSmall",p&&"inputHiddenLabel",u&&"inputAdornedStart",a&&"inputAdornedEnd",d&&"readOnly"]};return W(x,pE,t)},Us=k("div",{name:"MuiInputBase",slot:"Root",overridesResolver:js})(J(({theme:e})=>({...e.typography.body1,color:(e.vars||e).palette.text.primary,lineHeight:"1.4375em",boxSizing:"border-box",position:"relative",cursor:"text",display:"inline-flex",alignItems:"center",[`&.${Rn.disabled}`]:{color:(e.vars||e).palette.text.disabled,cursor:"default"},variants:[{props:({ownerState:t})=>t.multiline,style:{padding:"4px 0 5px"}},{props:({ownerState:t,size:o})=>t.multiline&&o==="small",style:{paddingTop:1}},{props:({ownerState:t})=>t.fullWidth,style:{width:"100%"}}]}))),Ls=k("input",{name:"MuiInputBase",slot:"Input",overridesResolver:Bs})(J(({theme:e})=>{let t=e.palette.mode==="light",o={color:"currentColor",...e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5},transition:e.transitions.create("opacity",{duration:e.transitions.duration.shorter})},r={opacity:"0 !important"},n=e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5};return{font:"inherit",letterSpacing:"inherit",color:"currentColor",padding:"4px 0 5px",border:0,boxSizing:"content-box",background:"none",height:"1.4375em",margin:0,WebkitTapHighlightColor:"transparent",display:"block",minWidth:0,width:"100%","&::-webkit-input-placeholder":o,"&::-moz-placeholder":o,"&::-ms-input-placeholder":o,"&:focus":{outline:0},"&:invalid":{boxShadow:"none"},"&::-webkit-search-decoration":{WebkitAppearance:"none"},[`label[data-shrink=false] + .${Rn.formControl} &`]:{"&::-webkit-input-placeholder":r,"&::-moz-placeholder":r,"&::-ms-input-placeholder":r,"&:focus::-webkit-input-placeholder":n,"&:focus::-moz-placeholder":n,"&:focus::-ms-input-placeholder":n},[`&.${Rn.disabled}`]:{opacity:1,WebkitTextFillColor:(e.vars||e).palette.text.disabled},variants:[{props:({ownerState:a})=>!a.disableInjectingGlobalStyles,style:{animationName:Xm,animationDuration:"10ms","&:-webkit-autofill":{animationDuration:"5000s",animationName:sb}}},{props:{size:"small"},style:{paddingTop:1}},{props:({ownerState:a})=>a.multiline,style:{height:"auto",resize:"none",padding:0,paddingTop:0}},{props:{type:"search"},style:{MozAppearance:"textfield"}}]}})),uE=lu({[`@keyframes ${sb}`]:{from:{animationName:sb}},[`@keyframes ${Xm}`]:{from:{animationName:Xm}}}),l6=Vo.forwardRef(function(t,o){let r=Q({props:t,name:"MuiInputBase"}),{"aria-describedby":n,autoComplete:a,autoFocus:i,className:s,color:l,components:p={},componentsProps:c={},defaultValue:d,disabled:f,disableInjectingGlobalStyles:u,endAdornment:g,error:x,fullWidth:v=!1,id:m,inputComponent:y="input",inputProps:h={},inputRef:T,margin:P,maxRows:S,minRows:E,multiline:R=!1,name:w,onBlur:O,onChange:A,onClick
Line truncated
|
||||
0% {
|
||||
left: -35%;
|
||||
right: 100%;
|
||||
@@ -159,9 +159,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
left: 100%;
|
||||
right: -90%;
|
||||
}
|
||||
`,J6=typeof gb!="string"?ir`
|
||||
animation: ${gb} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
`:null,Tb=vo`
|
||||
`,lB=typeof Cb!="string"?pr`
|
||||
animation: ${Cb} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
`:null,Eb=Ro`
|
||||
0% {
|
||||
left: -200%;
|
||||
right: 100%;
|
||||
@@ -176,9 +176,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
left: 107%;
|
||||
right: -8%;
|
||||
}
|
||||
`,eB=typeof Tb!="string"?ir`
|
||||
animation: ${Tb} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite;
|
||||
`:null,bb=vo`
|
||||
`,pB=typeof Eb!="string"?pr`
|
||||
animation: ${Eb} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite;
|
||||
`:null,Rb=Ro`
|
||||
0% {
|
||||
opacity: 1;
|
||||
background-position: 0 -23px;
|
||||
@@ -193,9 +193,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
opacity: 1;
|
||||
background-position: -200px -23px;
|
||||
}
|
||||
`,tB=typeof bb!="string"?ir`
|
||||
animation: ${bb} 3s infinite linear;
|
||||
`:null,oB=e=>{let{classes:t,variant:o,color:r}=e,n={root:["root",`color${j(r)}`,o],dashed:["dashed",`dashedColor${j(r)}`],bar1:["bar","bar1",`barColor${j(r)}`,(o==="indeterminate"||o==="query")&&"bar1Indeterminate",o==="determinate"&&"bar1Determinate",o==="buffer"&&"bar1Buffer"],bar2:["bar","bar2",o!=="buffer"&&`barColor${j(r)}`,o==="buffer"&&`color${j(r)}`,(o==="indeterminate"||o==="query")&&"bar2Indeterminate",o==="buffer"&&"bar2Buffer"]};return Y(n,gR,t)},vb=(e,t)=>e.vars?e.vars.palette.LinearProgress[`${t}Bg`]:e.palette.mode==="light"?e.lighten(e.palette[t].main,.62):e.darken(e.palette[t].main,.5),rB=D("span",{name:"MuiLinearProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[`color${j(o.color)}`],t[o.variant]]}})(Z(({theme:e})=>({position:"relative",overflow:"hidden",display:"block",height:4,zIndex:0,"@media print":{colorAdjust:"exact"},variants:[...Object.entries(e.palette).filter(Be()).map(([t])=>({props:{color:t},style:{backgroundColor:vb(e,t)}})),{props:({ownerState:t})=>t.color==="inherit"&&t.variant!=="buffer",style:{"&::before":{content:'""',position:"absolute",left:0,top:0,right:0,bottom:0,backgroundColor:"currentColor",opacity:.3}}},{props:{variant:"buffer"},style:{backgroundColor:"transparent"}},{props:{variant:"query"},style:{transform:"rotate(180deg)"}}]}))),nB=D("span",{name:"MuiLinearProgress",slot:"Dashed",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.dashed,t[`dashedColor${j(o.color)}`]]}})(Z(({theme:e})=>({position:"absolute",marginTop:0,height:"100%",width:"100%",backgroundSize:"10px 10px",backgroundPosition:"0 -23px",variants:[{props:{color:"inherit"},style:{opacity:.3,backgroundImage:"radial-gradient(currentColor 0%, currentColor 16%, transparent 42%)"}},...Object.entries(e.palette).filter(Be()).map(([t])=>{let o=vb(e,t);return{props:{color:t},style:{backgroundImage:`radial-gradient(${o} 0%, ${o} 16%, transparent 42%)`}}})]})),tB||{animation:`${bb} 3s infinite linear`}),aB=D("span",{name:"MuiLinearProgress",slot:"Bar1",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar1,t[`barColor${j(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar1Indeterminate,o.variant==="determinate"&&t.bar1Determinate,o.variant==="buffer"&&t.bar1Buffer]}})(Z(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[{props:{color:"inherit"},style:{backgroundColor:"currentColor"}},...Object.entries(e.palette).filter(Be()).map(([t])=>({props:{color:t},style:{backgroundColor:(e.vars||e).palette[t].main}})),{props:{variant:"determinate"},style:{transition:`transform .${hb}s linear`}},{props:{variant:"buffer"},style:{zIndex:1,transition:`transform .${hb}s linear`}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:J6||{animation:`${gb} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite`}}]}))),iB=D("span",{name:"MuiLinearProgress",slot:"Bar2",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar2,t[`barColor${j(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar2Indeterminate,o.variant==="buffer"&&t.bar2Buffer]}})(Z(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[...Object.entries(e.palette).filter(Be()).map(([t])=>({props:{color:t},style:{"--LinearProgressBar2-barColor":(e.vars||e).palette[t].main}})),{props:({ownerState:t})=>t.variant!=="buffer"&&t.color!=="inherit",style:{backgroundColor:"var(--LinearProgressBar2-barColor, currentColor)"}},{props:({ownerState:t})=>t.variant!=="buffer"&&t.color==="inherit",style:{backgroundColor:"currentColor"}},{props:{color:"inherit"},style:{opacity:.3}},...Object.entries(e.palette).filter(Be()).map(([t])=>({props:{color:t,variant:"buffer"},style:{backgroundColor:vb(e,t),transition:`transform .${hb}s linear`}})),{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:eB||{animation:`${Tb} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite`}}]}))),sB=TR.forwardRef(function(t,o){let r=X({props:t,name:"MuiLinearProgress"}),{className:n,color:a="primary",value:i,valueBuffer:s,variant:l="indeterminate",...p}=r,c={...r,color:a,variant:l},m=oB(c),f=ai(),u={},g={bar1:{},bar2:{}};if((l==="determinate"||l==="buffer")&&i!==void 0){u["aria-valuenow"]=Math.round(i),u["aria-valuemin"]=0,u["aria-valuemax"]=100;let v=i-100;f&&(v=-v),g.bar1.transform=`translateX(${v}%)`}if(l==="buffer"&&s!==void 0){let v=(s||0)-100;f&&(v=-v),g.bar2.transform=`translateX(${v}%)`}return(0,hp.jsxs)(rB,{className:L(m.root,n),ownerState:c,role:"progressbar",...u,ref:o,...p,children:[l==="buffer"?(0,hp.jsx)(nB,{className:m.dashed,ownerState:c}):null,(0,hp.jsx)(aB,{className:m.bar1,ownerState:c
Line truncated
|
||||
`,cB=typeof Rb!="string"?pr`
|
||||
animation: ${Rb} 3s infinite linear;
|
||||
`:null,uB=e=>{let{classes:t,variant:o,color:r}=e,n={root:["root",`color${B(r)}`,o],dashed:["dashed",`dashedColor${B(r)}`],bar1:["bar","bar1",`barColor${B(r)}`,(o==="indeterminate"||o==="query")&&"bar1Indeterminate",o==="determinate"&&"bar1Determinate",o==="buffer"&&"bar1Buffer"],bar2:["bar","bar2",o!=="buffer"&&`barColor${B(r)}`,o==="buffer"&&`color${B(r)}`,(o==="indeterminate"||o==="query")&&"bar2Indeterminate",o==="buffer"&&"bar2Buffer"]};return W(n,CR,t)},Ob=(e,t)=>e.vars?e.vars.palette.LinearProgress[`${t}Bg`]:e.palette.mode==="light"?e.lighten(e.palette[t].main,.62):e.darken(e.palette[t].main,.5),fB=k("span",{name:"MuiLinearProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[`color${B(o.color)}`],t[o.variant]]}})(J(({theme:e})=>({position:"relative",overflow:"hidden",display:"block",height:4,zIndex:0,"@media print":{colorAdjust:"exact"},variants:[...Object.entries(e.palette).filter(Ue()).map(([t])=>({props:{color:t},style:{backgroundColor:Ob(e,t)}})),{props:({ownerState:t})=>t.color==="inherit"&&t.variant!=="buffer",style:{"&::before":{content:'""',position:"absolute",left:0,top:0,right:0,bottom:0,backgroundColor:"currentColor",opacity:.3}}},{props:{variant:"buffer"},style:{backgroundColor:"transparent"}},{props:{variant:"query"},style:{transform:"rotate(180deg)"}}]}))),dB=k("span",{name:"MuiLinearProgress",slot:"Dashed",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.dashed,t[`dashedColor${B(o.color)}`]]}})(J(({theme:e})=>({position:"absolute",marginTop:0,height:"100%",width:"100%",backgroundSize:"10px 10px",backgroundPosition:"0 -23px",variants:[{props:{color:"inherit"},style:{opacity:.3,backgroundImage:"radial-gradient(currentColor 0%, currentColor 16%, transparent 42%)"}},...Object.entries(e.palette).filter(Ue()).map(([t])=>{let o=Ob(e,t);return{props:{color:t},style:{backgroundImage:`radial-gradient(${o} 0%, ${o} 16%, transparent 42%)`}}})]})),cB||{animation:`${Rb} 3s infinite linear`}),mB=k("span",{name:"MuiLinearProgress",slot:"Bar1",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar1,t[`barColor${B(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar1Indeterminate,o.variant==="determinate"&&t.bar1Determinate,o.variant==="buffer"&&t.bar1Buffer]}})(J(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[{props:{color:"inherit"},style:{backgroundColor:"currentColor"}},...Object.entries(e.palette).filter(Ue()).map(([t])=>({props:{color:t},style:{backgroundColor:(e.vars||e).palette[t].main}})),{props:{variant:"determinate"},style:{transition:`transform .${Sb}s linear`}},{props:{variant:"buffer"},style:{zIndex:1,transition:`transform .${Sb}s linear`}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:lB||{animation:`${Cb} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite`}}]}))),yB=k("span",{name:"MuiLinearProgress",slot:"Bar2",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar2,t[`barColor${B(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar2Indeterminate,o.variant==="buffer"&&t.bar2Buffer]}})(J(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[...Object.entries(e.palette).filter(Ue()).map(([t])=>({props:{color:t},style:{"--LinearProgressBar2-barColor":(e.vars||e).palette[t].main}})),{props:({ownerState:t})=>t.variant!=="buffer"&&t.color!=="inherit",style:{backgroundColor:"var(--LinearProgressBar2-barColor, currentColor)"}},{props:({ownerState:t})=>t.variant!=="buffer"&&t.color==="inherit",style:{backgroundColor:"currentColor"}},{props:{color:"inherit"},style:{opacity:.3}},...Object.entries(e.palette).filter(Ue()).map(([t])=>({props:{color:t,variant:"buffer"},style:{backgroundColor:Ob(e,t),transition:`transform .${Sb}s linear`}})),{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:pB||{animation:`${Eb} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite`}}]}))),hB=ER.forwardRef(function(t,o){let r=Q({props:t,name:"MuiLinearProgress"}),{className:n,color:a="primary",value:i,valueBuffer:s,variant:l="indeterminate",...p}=r,c={...r,color:a,variant:l},d=uB(c),f=ci(),u={},g={bar1:{},bar2:{}};if((l==="determinate"||l==="buffer")&&i!==void 0){u["aria-valuenow"]=Math.round(i),u["aria-valuemin"]=0,u["aria-valuemax"]=100;let x=i-100;f&&(x=-x),g.bar1.transform=`translateX(${x}%)`}if(l==="buffer"&&s!==void 0){let x=(s||0)-100;f&&(x=-x),g.bar2.transform=`translateX(${x}%)`}return(0,Cp.jsxs)(fB,{className:L(d.root,n),ownerState:c,role:"progressbar",...u,ref:o,...p,children:[l==="buffer"?(0,Cp.jsx)(dB,{className:d.dashed,ownerState:c}):null,(0,Cp.jsx)(mB,{className:d.bar1,ownerState:c
Line truncated
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
@@ -207,7 +207,7 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
100% {
|
||||
opacity: 1;
|
||||
}
|
||||
`,jb=vo`
|
||||
`,Vb=Ro`
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
@@ -220,22 +220,22 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
100% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
`,u9=typeof zb!="string"?ir`
|
||||
animation: ${zb} 2s ease-in-out 0.5s infinite;
|
||||
`:null,f9=typeof jb!="string"?ir`
|
||||
`,v9=typeof Hb!="string"?pr`
|
||||
animation: ${Hb} 2s ease-in-out 0.5s infinite;
|
||||
`:null,x9=typeof Vb!="string"?pr`
|
||||
&::after {
|
||||
animation: ${jb} 2s linear 0.5s infinite;
|
||||
animation: ${Vb} 2s linear 0.5s infinite;
|
||||
}
|
||||
`:null,d9=D("span",{name:"MuiSkeleton",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[o.variant],o.animation!==!1&&t[o.animation],o.hasChildren&&t.withChildren,o.hasChildren&&!o.width&&t.fitContent,o.hasChildren&&!o.height&&t.heightAuto]}})(Z(({theme:e})=>{let t=bT(e.shape.borderRadius)||"px",o=vT(e.shape.borderRadius);return{display:"block",backgroundColor:e.vars?e.vars.palette.Skeleton.bg:e.alpha(e.palette.text.primary,e.palette.mode==="light"?.11:.13),height:"1.2em",variants:[{props:{variant:"text"},style:{marginTop:0,marginBottom:0,height:"auto",transformOrigin:"0 55%",transform:"scale(1, 0.60)",borderRadius:`${o}${t}/${Math.round(o/.6*10)/10}${t}`,"&:empty:before":{content:'"\\00a0"'}}},{props:{variant:"circular"},style:{borderRadius:"50%"}},{props:{variant:"rounded"},style:{borderRadius:(e.vars||e).shape.borderRadius}},{props:({ownerState:r})=>r.hasChildren,style:{"& > *":{visibility:"hidden"}}},{props:({ownerState:r})=>r.hasChildren&&!r.width,style:{maxWidth:"fit-content"}},{props:({ownerState:r})=>r.hasChildren&&!r.height,style:{height:"auto"}},{props:{animation:"pulse"},style:u9||{animation:`${zb} 2s ease-in-out 0.5s infinite`}},{props:{animation:"wave"},style:{position:"relative",overflow:"hidden",WebkitMaskImage:"-webkit-radial-gradient(white, black)","&::after":{background:`linear-gradient(
|
||||
`:null,P9=k("span",{name:"MuiSkeleton",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[o.variant],o.animation!==!1&&t[o.animation],o.hasChildren&&t.withChildren,o.hasChildren&&!o.width&&t.fitContent,o.hasChildren&&!o.height&&t.heightAuto]}})(J(({theme:e})=>{let t=RT(e.shape.borderRadius)||"px",o=OT(e.shape.borderRadius);return{display:"block",backgroundColor:e.vars?e.vars.palette.Skeleton.bg:e.alpha(e.palette.text.primary,e.palette.mode==="light"?.11:.13),height:"1.2em",variants:[{props:{variant:"text"},style:{marginTop:0,marginBottom:0,height:"auto",transformOrigin:"0 55%",transform:"scale(1, 0.60)",borderRadius:`${o}${t}/${Math.round(o/.6*10)/10}${t}`,"&:empty:before":{content:'"\\00a0"'}}},{props:{variant:"circular"},style:{borderRadius:"50%"}},{props:{variant:"rounded"},style:{borderRadius:(e.vars||e).shape.borderRadius}},{props:({ownerState:r})=>r.hasChildren,style:{"& > *":{visibility:"hidden"}}},{props:({ownerState:r})=>r.hasChildren&&!r.width,style:{maxWidth:"fit-content"}},{props:({ownerState:r})=>r.hasChildren&&!r.height,style:{height:"auto"}},{props:{animation:"pulse"},style:v9||{animation:`${Hb} 2s ease-in-out 0.5s infinite`}},{props:{animation:"wave"},style:{position:"relative",overflow:"hidden",WebkitMaskImage:"-webkit-radial-gradient(white, black)","&::after":{background:`linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
${(e.vars||e).palette.action.hover},
|
||||
transparent
|
||||
)`,content:'""',position:"absolute",transform:"translateX(-100%)",bottom:0,left:0,right:0,top:0}}},{props:{animation:"wave"},style:f9||{"&::after":{animation:`${jb} 2s linear 0.5s infinite`}}}]}})),m9=KR.forwardRef(function(t,o){let r=X({props:t,name:"MuiSkeleton"}),{animation:n="pulse",className:a,component:i="span",height:s,style:l,variant:p="text",width:c,...m}=r,f={...r,animation:n,component:i,variant:p,hasChildren:!!m.children},u=c9(f);return(0,WR.jsx)(d9,{as:i,ref:o,className:L(u.root,a),ownerState:f,...m,style:{width:c,height:s,...l}})}),Fu=m9;var xy=C(I(),1);var xp=C(I(),1);function y9(e={}){let{autoHideDuration:t=null,disableWindowBlurListener:o=!1,onClose:r,open:n,resumeHideDuration:a}=e,i=Ko();xp.useEffect(()=>{if(!n)return;function d(y){y.defaultPrevented||y.key==="Escape"&&r?.(y,"escapeKeyDown")}return document.addEventListener("keydown",d),()=>{document.removeEventListener("keydown",d)}},[n,r]);let s=Er((d,y)=>{r?.(d,y)}),l=Er(d=>{!r||d==null||i.start(d,()=>{s(null,"timeout")})});xp.useEffect(()=>(n&&l(t),i.clear),[n,t,l,i]);let p=d=>{r?.(d,"clickaway")},c=i.clear,m=xp.useCallback(()=>{t!=null&&l(a??t*.5)},[t,a,l]),f=d=>y=>{let h=d.onBlur;h?.(y),m()},u=d=>y=>{let h=d.onFocus;h?.(y),c()},g=d=>y=>{let h=d.onMouseEnter;h?.(y),c()},v=d=>y=>{let h=d.onMouseLeave;h?.(y),m()};return xp.useEffect(()=>{if(!o&&n)return window.addEventListener("focus",m),window.addEventListener("blur",c),()=>{window.removeEventListener("focus",m),window.removeEventListener("blur",c)}},[o,n,m,c]),{getRootProps:(d={})=>{let y={...pi(e),...pi(d)};return{role:"presentation",...d,...y,onBlur:f(y),onFocus:u(y),onMouseEnter:g(y),onMouseLeave:v(y)}},onClickAway:p}}var XR=y9;var ZR=C(I(),1);function QR(e){return q("MuiSnackbarContent",e)}var vbe=G("MuiSnackbarContent",["root","message","action"]);var qu=C(U(),1),h9=e=>{let{classes:t}=e;return Y({root:["root"],action:["action"],message:["message"]},QR,t)},g9=D(xt,{name:"MuiSnackbarContent",slot:"Root"})(Z(({theme:e})=>{let t=e.palette.mode==="light"?.8:.98;return{...e.typography.body2,color:e.vars?e.vars.palette.SnackbarContent.color:e.palette.getContrastText($d(e.palette.background.default,t)),backgroundColor:e.vars?e.vars.palette.SnackbarContent.bg:$d(e.palette.background.default,t),display:"flex",alignItems:"center",flexWrap:"wrap",padding:"6px 16px",flexGrow:1,[e.breakpoints.up("sm")]:{flexGrow:"initial",minWidth:288}}})),T9=D("div",{name:"MuiSnackbarContent",slot:"Message"})({padding:"8px 0"}),b9=D("div",{name:"MuiSnackbarContent",slot:"Action"})({display:"flex",alignItems:"center",marginLeft:"auto",paddingLeft:16,marginRight:-8}),v9=ZR.forwardRef(function(t,o){let r=X({props:t,name:"MuiSnackbarContent"}),{action:n,className:a,message:i,role:s="alert",...l}=r,p=r,c=h9(p);return(0,qu.jsxs)(g9,{role:s,elevation:6,className:L(c.root,a),ownerState:p,ref:o,...l,children:[(0,qu.jsx)(T9,{className:c.message,ownerState:p,children:i}),n?(0,qu.jsx)(b9,{className:c.action,ownerState:p,children:n}):null]})}),Bb=v9;function JR(e){return q("MuiSnackbar",e)}var jbe=G("MuiSnackbar",["root","anchorOriginTopCenter","anchorOriginBottomCenter","anchorOriginTopRight","anchorOriginBottomRight","anchorOriginTopLeft","anchorOriginBottomLeft"]);var Gu=C(U(),1),x9=e=>{let{classes:t,anchorOrigin:o}=e,r={root:["root",`anchorOrigin${j(o.vertical)}${j(o.horizontal)}`]};return Y(r,JR,t)},P9=D("div",{name:"MuiSnackbar",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[`anchorOrigin${j(o.anchorOrigin.vertical)}${j(o.anchorOrigin.horizontal)}`]]}})(Z(({theme:e})=>({zIndex:(e.vars||e).zIndex.snackbar,position:"fixed",display:"flex",left:8,right:8,justifyContent:"center",alignItems:"center",variants:[{props:({ownerState:t})=>t.anchorOrigin.vertical==="top",style:{top:8,[e.breakpoints.up("sm")]:{top:24}}},{props:({ownerState:t})=>t.anchorOrigin.vertical!=="top",style:{bottom:8,[e.breakpoints.up("sm")]:{bottom:24}}},{props:({ownerState:t})=>t.anchorOrigin.horizontal==="left",style:{justifyContent:"flex-start",[e.breakpoints.up("sm")]:{left:24,right:"auto"}}},{props:({ownerState:t})=>t.anchorOrigin.horizontal==="right",style:{justifyContent:"flex-end",[e.breakpoints.up("sm")]:{right:24,left:"auto"}}},{props:({ownerState:t})=>t.anchorOrigin.horizontal==="center",style:{[e.breakpoints.up("sm")]:{left:"50%",right:"auto",transform:"translateX(-50%)"}}}]}))),S9=xy.forwardRef(function(t,o){let r=X({props:t,name:"MuiSnackbar"}),n=Dt(),a={enter:n.transitions.duration.enteringScreen,exit:n.transitions.duration.leavingScreen},{action:i,anchorOrigin:{vertical:s,horizontal:l}={vertical:"bottom",horizontal:"left"},autoHideDuration:p=null,children:c,className:m,ClickAwayListenerProps:f,ContentProps:u,disableWindowBlurListener:g=!1,message:v,onBlur:x,onClose:d,onFocus:y,onMouseEnter:h,onMouseLeave:T,open:P,resumeHideDuration:S,slots:E={},slotProps:R={},TransitionComponent:w,transitionDuration:O=a,TransitionProps:{onEnter:N,onExited:b,...M}={},...A}=r,_={...r,anchorOrigin:{vertical:s,horizon
Line truncated
|
||||
${e.palette.mode==="light"?e.lighten(e.alpha(e.palette.divider,1),.88):e.darken(e.alpha(e.palette.divider,1),.68)}`,textAlign:"left",padding:16,variants:[{props:{variant:"head"},style:{color:(e.vars||e).palette.text.primary,lineHeight:e.typography.pxToRem(24),fontWeight:e.typography.fontWeightMedium}},{props:{variant:"body"},style:{color:(e.vars||e).palette.text.primary}},{props:{variant:"footer"},style:{color:(e.vars||e).palette.text.secondary,lineHeight:e.typography.pxToRem(21),fontSize:e.typography.pxToRem(12)}},{props:{size:"small"},style:{padding:"6px 16px",[`&.${c2.paddingCheckbox}`]:{width:24,padding:"0 12px 0 16px","& > *":{padding:0}}}},{props:{padding:"checkbox"},style:{width:48,padding:"0 0 0 4px"}},{props:{padding:"none"},style:{padding:0}},{props:{align:"left"},style:{textAlign:"left"}},{props:{align:"center"},style:{textAlign:"center"}},{props:{align:"right"},style:{textAlign:"right",flexDirection:"row-reverse"}},{props:{align:"justify"},style:{textAlign:"justify"}},{props:({ownerState:t})=>t.stickyHeader,style:{position:"sticky",top:0,zIndex:2,backgroundColor:(e.vars||e).palette.background.default}}]}))),F9=Ku.forwardRef(function(t,o){let r=X({props:t,name:"MuiTableCell"}),{align:n="inherit",className:a,component:i,padding:s,scope:l,size:p,sortDirection:c,variant:m,...f}=r,u=Ku.useContext(Ey),g=Ku.useContext(Ti),v=g&&g.variant==="head",x;i?x=i:x=v?"th":"td";let d=l;x==="td"?d=void 0:!d&&v&&(d="col");let y=m||g&&g.variant,h={...r,align:n,component:x,padding:s||(u&&u.padding?u.padding:"normal"),size:p||(u&&u.size?u.size:"medium"),sortDirection:c,stickyHeader:y==="head"&&u&&u.stickyHeader,variant:y},T=$9(h),P=null;return c&&(P=c==="asc"?"ascending":"descending"),(0,u2.jsx)(V9,{as:x,ref:o,className:L(T.root,a),"aria-sort":P,scope:d,ownerState:h,...f})}),Kt=F9;var d2=C(I(),1);function f2(e){return q("MuiTableContainer",e)}var E0e=G("MuiTableContainer",["root"]);var m2=C(U(),1),q9=e=>{let{classes:t}=e;return Y({root:["root"]},f2,t)},G9=D("div",{name:"MuiTableContainer",slot:"Root"})({width:"100%",overflowX:"auto"}),Y9=d2.forwardRef(function(t,o){let r=X({props:t,name:"MuiTableContainer"}),{className:n,component:a="div",...i}=r,s={...r,component:a},l=q9(s);return(0,m2.jsx)(G9,{ref:o,as:a,className:L(l.root,n),ownerState:s,...i})}),Cp=Y9;var g2=C(I(),1);function y2(e){return q("MuiTableHead",e)}var U0e=G("MuiTableHead",["root"]);var Ib=C(U(),1),K9=e=>{let{classes:t}=e;return Y({root:["root"]},y2,t)},W9=D("thead",{name:"MuiTableHead",slot:"Root"})({display:"table-header-group"}),X9={variant:"head"},h2="thead",Q9=g2.forwardRef(function(t,o){let r=X({props:t,name:"MuiTableHead"}),{className:n,component:a=h2,...i}=r,s={...r,component:a},l=K9(s);return(0,Ib.jsx)(Ti.Provider,{value:X9,children:(0,Ib.jsx)(W9,{as:a,className:L(l.root,n),ref:o,role:a===h2?null:"rowgroup",ownerState:s,...i})})}),Ep=Q9;var Oy=C(I(),1);function T2(e){return q("MuiTableRow",e)}var Z9=G("MuiTableRow",["root","selected","hover","head","footer"]),Hb=Z9;var v2=C(U(),1),J9=e=>{let{classes:t,selected:o,hover:r,head:n,footer:a}=e;return Y({root:["root",o&&"selected",r&&"hover",n&&"head",a&&"footer"]},T2,t)},eU=D("tr",{name:"MuiTableRow",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,o.head&&t.head,o.footer&&t.footer]}})(Z(({theme:e})=>({color:"inherit",display:"table-row",verticalAlign:"middle",outline:0,[`&.${Hb.hover}:hover`]:{backgroundColor:(e.vars||e).palette.action.hover},[`&.${Hb.selected}`]:{backgroundColor:e.alpha((e.vars||e).palette.primary.main,(e.vars||e).palette.action.selectedOpacity),"&:hover":{backgroundColor:e.alpha((e.vars||e).palette.primary.main,`${(e.vars||e).palette.action.selectedOpacity} + ${(e.vars||e).palette.action.hoverOpacity}`)}}}))),b2="tr",tU=Oy.forwardRef(function(t,o){let r=X({props:t,name:"MuiTableRow"}),{className:n,component:a=b2,hover:i=!1,selected:s=!1,...l}=r,p=Oy.useContext(Ti),c={...r,component:a,hover:i,selected:s,head:p&&p.variant==="head",footer:p&&p.variant==="footer"},m=J9(c);return(0,v2.jsx)(eU,{as:a,ref:o,className:L(m.root,n),role:a===b2?null:"row",ownerState:c,...l})}),za=tU;var P2=C(I(),1);function x2(e){return q("MuiTextField",e)}var fxe=G("MuiTextField",["root"]);var js=C(U(),1),oU={standard:_u,filled:Du,outlined:$u},rU=e=>{let{classes:t}=e;return Y({root:["root"]},x2,t)},nU=D(lb,{name:"MuiTextField",slot:"Root"})({}),aU=P2.forwardRef(function(t,o){let r=X({props:t,name:"MuiTextField"}),{autoComplete:n,autoFocus:a=!1,children:i,className:s,color:l="primary",defaultValue:p,disabled:c=!1,error:m=!1,FormHelperTextProps:f,fullWidth:u=!1,helperText:g,id:v,InputLabelProps:x,inputProps:d,InputProps:y,inputRef:h,label:T,maxRows:P,minRows:S,multiline:E=!1,name:R,onBlur:w,onChange:O,onFocus:N,placeholder:b,required:M=!1,rows:A,select:_=!1,SelectProps:k,slots:W={},slotProps:re={},type:F,value:me,variant:ie="outlined",...ue}=r,ne={...r,autoFocus:a,color:l,disabled:c,error:m,fullWidth:u,multiline:E,required:M,select:_,variant:ie},Ee=rU(ne),le=Yr(v),oe=g&&le?`${le}-heLine truncated
|
||||
`):e[i]),o(i),n(!1)}catch{o(null),n(!0)}}return(0,tr.jsxs)(he,{sx:{my:2},children:[(0,tr.jsxs)(Ce,{direction:"row",alignItems:"center",justifyContent:"space-between",spacing:1,sx:{mb:1},children:[(0,tr.jsx)(K,{variant:"body2",color:"text.secondary",children:"\u70B9\u51FB\u5355\u679A\u5151\u6362\u7801\u5373\u53EF\u590D\u5236"}),(0,tr.jsx)(Se,{size:"small",color:"secondary",startIcon:(0,tr.jsx)($x,{}),onClick:()=>{a("all")},sx:{px:1.5,flexShrink:0},children:"\u590D\u5236\u5168\u90E8"})]}),(0,tr.jsx)(he,{component:"ul","aria-label":"\u65B0\u751F\u6210\u7684\u5151\u6362\u7801",sx:{m:0,p:0,listStyle:"none",maxHeight:300,overflowY:"auto",border:1,borderColor:"divider",borderRadius:2},children:e.map((i,s)=>(0,tr.jsx)(he,{component:"li",children:(0,tr.jsx)(Se,{fullWidth:!0,"aria-label":`\u590D\u5236\u7B2C ${s+1} \u679A\u5151\u6362\u7801`,onClick:()=>{a(s)},endIcon:t===s?(0,tr.jsx)(eA,{}):(0,tr.jsx)($x,{}),sx:{py:1.5,px:2,borderRadius:0,justifyContent:"space-between",textAlign:"left",borderBottom:s<e.length-1?1:0,borderColor:"divider",color:"text.primary",gap:1},children:(0,tr.jsx)(he,{component:"code",sx:{fontFamily:"monospace",fontSize:".8125rem",overflowWrap:"anywhere",userSelect:"text"},children:i})})},i))}),t!==null&&(0,tr.jsx)(K,{role:"status",variant:"body2",color:"success.main",sx:{mt:1},children:t==="all"?`\u5DF2\u590D\u5236\u5168\u90E8 ${e.length} \u679A\u5151\u6362\u7801\u3002`:`\u5DF2\u590D\u5236\u7B2C ${t+1} \u679A\u5151\u6362\u7801\u3002`}),r&&(0,tr.jsx)(gt,{severity:"warning",sx:{mt:1},children:"\u6D4F\u89C8\u5668\u672A\u5141\u8BB8\u8BBF\u95EE\u526A\u8D34\u677F\u3002\u8BF7\u9009\u4E2D\u5151\u6362\u7801\u624B\u52A8\u590D\u5236\uFF0C\u6216\u4F7F\u7528\u4E0B\u65B9\u300C\u4E0B\u8F7D TXT\u300D\u3002"})]})}async function or(e,t){let{ok:o,data:r}=await $M(e,t);if(!o)throw new Error(r.message||"\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");return r}function oA(){return or("/api/admin/stats")}var Zf=C(I(),1);var rA=C(U(),1),nA=ce((0,rA.jsx)("path",{d:"m9.17 6 2 2H20v10H4V6zM10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8z"}),"FolderOutlined");var aA=C(U(),1),iA=ce((0,aA.jsx)("path",{d:"m14.06 9.02.92.92L5.92 19H5v-.92zM17.66 3c-.25 0-.51.1-.7.29l-1.83 1.83 3.75 3.75 1.83-1.83c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.2-.2-.45-.29-.71-.29m-3.6 3.19L3 17.25V21h3.75L17.81 9.94z"}),"EditOutlined");var Ot=C(U(),1);function sA({folders:e,stats:t,filter:o,disabled:r,muted:n=!1,onSelect:a,onBusyChange:i,onChanged:s}){let[l,p]=(0,Zf.useState)(null),[c,m]=(0,Zf.useState)(""),[f,u]=(0,Zf.useState)(""),[g,v]=(0,Zf.useState)(!1);async function x(){if(!(!l||g)){if(!c.trim()||new TextEncoder().encode(c.trim()).length>120){u("\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u6700\u591A 120 \u5B57\u8282\u3002");return}v(!0),i(!0);try{await or("/api/admin/folders/rename",{id:l.id,name:c.trim()}),await s(),p(null)}catch(d){u(d.message)}finally{v(!1),i(!1)}}}return(0,Ot.jsxs)(he,{sx:{mb:3},children:[(0,Ot.jsxs)(Ce,{direction:"row",justifyContent:"space-between",alignItems:"baseline",sx:{mb:1.5},children:[(0,Ot.jsx)(K,{variant:"h2",children:"\u6279\u6B21"}),(0,Ot.jsxs)(K,{variant:"body2",color:"text.secondary",children:[t?.total??"\u2014"," \u679A\u5151\u6362\u7801"]})]}),(0,Ot.jsx)(K,{variant:"body2",color:"text.secondary",sx:{mb:2},children:"\u70B9\u51FB\u6279\u6B21\u6587\u4EF6\u5939\u67E5\u770B\u5151\u6362\u7801\uFF0C\u5DE6\u53F3\u6ED1\u52A8\u53EF\u67E5\u770B\u5168\u90E8\u6279\u6B21\u3002"}),(0,Ot.jsx)(Ce,{direction:"row",useFlexGap:!0,gap:1,sx:{height:80,overflowX:"auto",alignItems:"center",pb:1,opacity:n?.55:1,transition:"opacity 160ms ease"},role:"region","aria-label":"\u6279\u6B21\u6587\u4EF6\u5939\uFF0C\u53EF\u6A2A\u5411\u6EDA\u52A8",tabIndex:0,children:[{id:"",name:"\u5168\u90E8\u5151\u6362\u7801",count:t?.total??0},...t?.unfiled?[{id:"unfiled",name:"\u672A\u5206\u7C7B",count:t.unfiled}]:[],...e].map(d=>(0,Ot.jsxs)(he,{sx:{display:"flex",border:1,borderColor:o===d.id?"primary.main":"divider",borderRadius:2,bgcolor:o===d.id?"action.selected":"background.paper",maxWidth:"100%",flexShrink:0},children:[(0,Ot.jsxs)(Se,{disabled:r,"aria-pressed":o===d.id,startIcon:(0,Ot.jsx)(nA,{}),onClick:()=>a(d.id),sx:{px:2,py:1.5,justifyContent:"flex-start",textAlign:"left",overflowWrap:"anywhere",minWidth:0},children:[d.name," \xB7 ",d.count]}),d.id&&d.id!=="unfiled"&&(0,Ot.jsx)(kn,{describeChild:!0,title:`\u91CD\u547D\u540D\u6279\u6B21\uFF1A${d.name}`,children:(0,Ot.jsx)("span",{children:(0,Ot.jsx)(Xr,{"aria-label":`\u91CD\u547D\u540D\u6279\u6B21\uFF1A${d.name}`,disabled:r,onClick:()=>{p(d),m(d.name),u("")},sx:{m:.5,border:1,borderColor:"divider",width:44,height:44},children:(0,Ot.jsx)(iA,{fontSize:"small"})})})})]},d.id))}),(0,Ot.jsx)(Nn,{open:!!l,onClose:()=>!g&&p(null),fullWidth:!0,maxWidth:"xs","aria-labelledby":"batch-rename-title",children:(0,Ot.jsxs)(he,{component:"form",onSubmit:d=>{d.preventDefault(),x()},children:[(0,Ot.jsx)(Dn,{id:"batch-rename-title",children:"\u91CD\u547D\u540D
Line truncated
|
||||
)`,content:'""',position:"absolute",transform:"translateX(-100%)",bottom:0,left:0,right:0,top:0}}},{props:{animation:"wave"},style:x9||{"&::after":{animation:`${Vb} 2s linear 0.5s infinite`}}}]}})),S9=t2.forwardRef(function(t,o){let r=Q({props:t,name:"MuiSkeleton"}),{animation:n="pulse",className:a,component:i="span",height:s,style:l,variant:p="text",width:c,...d}=r,f={...r,animation:n,component:i,variant:p,hasChildren:!!d.children},u=b9(f);return(0,o2.jsx)(P9,{as:i,ref:o,className:L(u.root,a),ownerState:f,...d,style:{width:c,height:s,...l}})}),Qu=S9;var Ny=C(I(),1);var Mp=C(I(),1);function C9(e={}){let{autoHideDuration:t=null,disableWindowBlurListener:o=!1,onClose:r,open:n,resumeHideDuration:a}=e,i=Zo();Mp.useEffect(()=>{if(!n)return;function m(y){y.defaultPrevented||y.key==="Escape"&&r?.(y,"escapeKeyDown")}return document.addEventListener("keydown",m),()=>{document.removeEventListener("keydown",m)}},[n,r]);let s=Rr((m,y)=>{r?.(m,y)}),l=Rr(m=>{!r||m==null||i.start(m,()=>{s(null,"timeout")})});Mp.useEffect(()=>(n&&l(t),i.clear),[n,t,l,i]);let p=m=>{r?.(m,"clickaway")},c=i.clear,d=Mp.useCallback(()=>{t!=null&&l(a??t*.5)},[t,a,l]),f=m=>y=>{let h=m.onBlur;h?.(y),d()},u=m=>y=>{let h=m.onFocus;h?.(y),c()},g=m=>y=>{let h=m.onMouseEnter;h?.(y),c()},x=m=>y=>{let h=m.onMouseLeave;h?.(y),d()};return Mp.useEffect(()=>{if(!o&&n)return window.addEventListener("focus",d),window.addEventListener("blur",c),()=>{window.removeEventListener("focus",d),window.removeEventListener("blur",c)}},[o,n,d,c]),{getRootProps:(m={})=>{let y={...mi(e),...mi(m)};return{role:"presentation",...m,...y,onBlur:f(y),onFocus:u(y),onMouseEnter:g(y),onMouseLeave:x(y)}},onClickAway:p}}var r2=C9;var a2=C(I(),1);function n2(e){return G("MuiSnackbarContent",e)}var wbe=Y("MuiSnackbarContent",["root","message","action"]);var Zu=C(z(),1),E9=e=>{let{classes:t}=e;return W({root:["root"],action:["action"],message:["message"]},n2,t)},R9=k(dt,{name:"MuiSnackbarContent",slot:"Root"})(J(({theme:e})=>{let t=e.palette.mode==="light"?.8:.98;return{...e.typography.body2,color:e.vars?e.vars.palette.SnackbarContent.color:e.palette.getContrastText(Xd(e.palette.background.default,t)),backgroundColor:e.vars?e.vars.palette.SnackbarContent.bg:Xd(e.palette.background.default,t),display:"flex",alignItems:"center",flexWrap:"wrap",padding:"6px 16px",flexGrow:1,[e.breakpoints.up("sm")]:{flexGrow:"initial",minWidth:288}}})),O9=k("div",{name:"MuiSnackbarContent",slot:"Message"})({padding:"8px 0"}),w9=k("div",{name:"MuiSnackbarContent",slot:"Action"})({display:"flex",alignItems:"center",marginLeft:"auto",paddingLeft:16,marginRight:-8}),N9=a2.forwardRef(function(t,o){let r=Q({props:t,name:"MuiSnackbarContent"}),{action:n,className:a,message:i,role:s="alert",...l}=r,p=r,c=E9(p);return(0,Zu.jsxs)(R9,{role:s,elevation:6,className:L(c.root,a),ownerState:p,ref:o,...l,children:[(0,Zu.jsx)(O9,{className:c.message,ownerState:p,children:i}),n?(0,Zu.jsx)(w9,{className:c.action,ownerState:p,children:n}):null]})}),Fb=N9;function i2(e){return G("MuiSnackbar",e)}var Fbe=Y("MuiSnackbar",["root","anchorOriginTopCenter","anchorOriginBottomCenter","anchorOriginTopRight","anchorOriginBottomRight","anchorOriginTopLeft","anchorOriginBottomLeft"]);var Ju=C(z(),1),M9=e=>{let{classes:t,anchorOrigin:o}=e,r={root:["root",`anchorOrigin${B(o.vertical)}${B(o.horizontal)}`]};return W(r,i2,t)},A9=k("div",{name:"MuiSnackbar",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[`anchorOrigin${B(o.anchorOrigin.vertical)}${B(o.anchorOrigin.horizontal)}`]]}})(J(({theme:e})=>({zIndex:(e.vars||e).zIndex.snackbar,position:"fixed",display:"flex",left:8,right:8,justifyContent:"center",alignItems:"center",variants:[{props:({ownerState:t})=>t.anchorOrigin.vertical==="top",style:{top:8,[e.breakpoints.up("sm")]:{top:24}}},{props:({ownerState:t})=>t.anchorOrigin.vertical!=="top",style:{bottom:8,[e.breakpoints.up("sm")]:{bottom:24}}},{props:({ownerState:t})=>t.anchorOrigin.horizontal==="left",style:{justifyContent:"flex-start",[e.breakpoints.up("sm")]:{left:24,right:"auto"}}},{props:({ownerState:t})=>t.anchorOrigin.horizontal==="right",style:{justifyContent:"flex-end",[e.breakpoints.up("sm")]:{right:24,left:"auto"}}},{props:({ownerState:t})=>t.anchorOrigin.horizontal==="center",style:{[e.breakpoints.up("sm")]:{left:"50%",right:"auto",transform:"translateX(-50%)"}}}]}))),k9=Ny.forwardRef(function(t,o){let r=Q({props:t,name:"MuiSnackbar"}),n=jt(),a={enter:n.transitions.duration.enteringScreen,exit:n.transitions.duration.leavingScreen},{action:i,anchorOrigin:{vertical:s,horizontal:l}={vertical:"bottom",horizontal:"left"},autoHideDuration:p=null,children:c,className:d,ClickAwayListenerProps:f,ContentProps:u,disableWindowBlurListener:g=!1,message:x,onBlur:v,onClose:m,onFocus:y,onMouseEnter:h,onMouseLeave:T,open:P,resumeHideDuration:S,slots:E={},slotProps:R={},TransitionComponent:w,transitionDuration:O=a,TransitionProps:{onEnter:A,onExited:b,...N}={},...M}=r,_={...r,anchorOrigin:{vertical:s,horizon
Line truncated
|
||||
${e.palette.mode==="light"?e.lighten(e.alpha(e.palette.divider,1),.88):e.darken(e.alpha(e.palette.divider,1),.68)}`,textAlign:"left",padding:16,variants:[{props:{variant:"head"},style:{color:(e.vars||e).palette.text.primary,lineHeight:e.typography.pxToRem(24),fontWeight:e.typography.fontWeightMedium}},{props:{variant:"body"},style:{color:(e.vars||e).palette.text.primary}},{props:{variant:"footer"},style:{color:(e.vars||e).palette.text.secondary,lineHeight:e.typography.pxToRem(21),fontSize:e.typography.pxToRem(12)}},{props:{size:"small"},style:{padding:"6px 16px",[`&.${g2.paddingCheckbox}`]:{width:24,padding:"0 12px 0 16px","& > *":{padding:0}}}},{props:{padding:"checkbox"},style:{width:48,padding:"0 0 0 4px"}},{props:{padding:"none"},style:{padding:0}},{props:{align:"left"},style:{textAlign:"left"}},{props:{align:"center"},style:{textAlign:"center"}},{props:{align:"right"},style:{textAlign:"right",flexDirection:"row-reverse"}},{props:{align:"justify"},style:{textAlign:"justify"}},{props:({ownerState:t})=>t.stickyHeader,style:{position:"sticky",top:0,zIndex:2,backgroundColor:(e.vars||e).palette.background.default}}]}))),J9=tf.forwardRef(function(t,o){let r=Q({props:t,name:"MuiTableCell"}),{align:n="inherit",className:a,component:i,padding:s,scope:l,size:p,sortDirection:c,variant:d,...f}=r,u=tf.useContext(Dy),g=tf.useContext(Ci),x=g&&g.variant==="head",v;i?v=i:v=x?"th":"td";let m=l;v==="td"?m=void 0:!m&&x&&(m="col");let y=d||g&&g.variant,h={...r,align:n,component:v,padding:s||(u&&u.padding?u.padding:"normal"),size:p||(u&&u.size?u.size:"medium"),sortDirection:c,stickyHeader:y==="head"&&u&&u.stickyHeader,variant:y},T=Q9(h),P=null;return c&&(P=c==="asc"?"ascending":"descending"),(0,T2.jsx)(Z9,{as:v,ref:o,className:L(T.root,a),"aria-sort":P,scope:m,ownerState:h,...f})}),Zt=J9;var v2=C(I(),1);function b2(e){return G("MuiTableContainer",e)}var D0e=Y("MuiTableContainer",["root"]);var x2=C(z(),1),eU=e=>{let{classes:t}=e;return W({root:["root"]},b2,t)},tU=k("div",{name:"MuiTableContainer",slot:"Root"})({width:"100%",overflowX:"auto"}),oU=v2.forwardRef(function(t,o){let r=Q({props:t,name:"MuiTableContainer"}),{className:n,component:a="div",...i}=r,s={...r,component:a},l=eU(s);return(0,x2.jsx)(tU,{ref:o,as:a,className:L(l.root,n),ownerState:s,...i})}),Dp=oU;var C2=C(I(),1);function P2(e){return G("MuiTableHead",e)}var G0e=Y("MuiTableHead",["root"]);var Yb=C(z(),1),rU=e=>{let{classes:t}=e;return W({root:["root"]},P2,t)},nU=k("thead",{name:"MuiTableHead",slot:"Root"})({display:"table-header-group"}),aU={variant:"head"},S2="thead",iU=C2.forwardRef(function(t,o){let r=Q({props:t,name:"MuiTableHead"}),{className:n,component:a=S2,...i}=r,s={...r,component:a},l=rU(s);return(0,Yb.jsx)(Ci.Provider,{value:aU,children:(0,Yb.jsx)(nU,{as:a,className:L(l.root,n),ref:o,role:a===S2?null:"rowgroup",ownerState:s,...i})})}),_p=iU;var zy=C(I(),1);function E2(e){return G("MuiTableRow",e)}var sU=Y("MuiTableRow",["root","selected","hover","head","footer"]),Wb=sU;var O2=C(z(),1),lU=e=>{let{classes:t,selected:o,hover:r,head:n,footer:a}=e;return W({root:["root",o&&"selected",r&&"hover",n&&"head",a&&"footer"]},E2,t)},pU=k("tr",{name:"MuiTableRow",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,o.head&&t.head,o.footer&&t.footer]}})(J(({theme:e})=>({color:"inherit",display:"table-row",verticalAlign:"middle",outline:0,[`&.${Wb.hover}:hover`]:{backgroundColor:(e.vars||e).palette.action.hover},[`&.${Wb.selected}`]:{backgroundColor:e.alpha((e.vars||e).palette.primary.main,(e.vars||e).palette.action.selectedOpacity),"&:hover":{backgroundColor:e.alpha((e.vars||e).palette.primary.main,`${(e.vars||e).palette.action.selectedOpacity} + ${(e.vars||e).palette.action.hoverOpacity}`)}}}))),R2="tr",cU=zy.forwardRef(function(t,o){let r=Q({props:t,name:"MuiTableRow"}),{className:n,component:a=R2,hover:i=!1,selected:s=!1,...l}=r,p=zy.useContext(Ci),c={...r,component:a,hover:i,selected:s,head:p&&p.variant==="head",footer:p&&p.variant==="footer"},d=lU(c);return(0,O2.jsx)(pU,{as:a,ref:o,className:L(d.root,n),role:a===R2?null:"row",ownerState:c,...l})}),La=cU;var N2=C(I(),1);function w2(e){return G("MuiTextField",e)}var vxe=Y("MuiTextField",["root"]);var Vs=C(z(),1),uU={standard:Hu,filled:Iu,outlined:Ku},fU=e=>{let{classes:t}=e;return W({root:["root"]},w2,t)},dU=k(yb,{name:"MuiTextField",slot:"Root"})({}),mU=N2.forwardRef(function(t,o){let r=Q({props:t,name:"MuiTextField"}),{autoComplete:n,autoFocus:a=!1,children:i,className:s,color:l="primary",defaultValue:p,disabled:c=!1,error:d=!1,FormHelperTextProps:f,fullWidth:u=!1,helperText:g,id:x,InputLabelProps:v,inputProps:m,InputProps:y,inputRef:h,label:T,maxRows:P,minRows:S,multiline:E=!1,name:R,onBlur:w,onChange:O,onFocus:A,placeholder:b,required:N=!1,rows:M,select:_=!1,SelectProps:D,slots:K={},slotProps:ee={},type:q,value:ye,variant:se="outlined",...ce}=r,oe={...r,autoFocus:a,color:l,disabled:c,error:d,fullWidth:u,multiline:E,required:N,select:_,variant:se},Ce=fU(oe),pe=Wr(x),re=g&&pe?`${pe}-heLine truncated
|
||||
`):e[i]),o(i),n(!1)}catch{o(null),n(!0)}}return(0,ir.jsxs)(ue,{sx:{my:2},children:[(0,ir.jsxs)(ve,{direction:"row",alignItems:"center",justifyContent:"space-between",spacing:1,sx:{mb:1},children:[(0,ir.jsx)(V,{variant:"body2",color:"text.secondary",children:"\u70B9\u51FB\u5355\u679A\u5151\u6362\u7801\u5373\u53EF\u590D\u5236"}),(0,ir.jsx)(be,{size:"small",color:"secondary",startIcon:(0,ir.jsx)(Kx,{}),onClick:()=>{a("all")},sx:{px:1.5,flexShrink:0},children:"\u590D\u5236\u5168\u90E8"})]}),(0,ir.jsx)(ue,{component:"ul","aria-label":"\u65B0\u751F\u6210\u7684\u5151\u6362\u7801",tabIndex:0,sx:{m:0,p:0,listStyle:"none",maxHeight:300,overflowY:"auto",border:1,borderColor:"divider",borderRadius:2},children:e.map((i,s)=>(0,ir.jsx)(ue,{component:"li",children:(0,ir.jsx)(be,{fullWidth:!0,"aria-label":`\u590D\u5236\u7B2C ${s+1} \u679A\u5151\u6362\u7801`,onClick:()=>{a(s)},endIcon:t===s?(0,ir.jsx)(s3,{}):(0,ir.jsx)(Kx,{}),sx:{py:1.5,px:2,borderRadius:0,justifyContent:"space-between",textAlign:"left",borderBottom:s<e.length-1?1:0,borderColor:"divider",color:"text.primary",gap:1},children:(0,ir.jsx)(ue,{component:"code",sx:{fontFamily:"monospace",fontSize:".8125rem",overflowWrap:"anywhere",userSelect:"text"},children:i})})},i))}),t!==null&&(0,ir.jsx)(V,{role:"status",variant:"body2",color:"success.main",sx:{mt:1},children:t==="all"?`\u5DF2\u590D\u5236\u5168\u90E8 ${e.length} \u679A\u5151\u6362\u7801\u3002`:`\u5DF2\u590D\u5236\u7B2C ${t+1} \u679A\u5151\u6362\u7801\u3002`}),r&&(0,ir.jsx)(pt,{severity:"warning",sx:{mt:1},children:"\u6D4F\u89C8\u5668\u672A\u5141\u8BB8\u8BBF\u95EE\u526A\u8D34\u677F\u3002\u8BF7\u9009\u4E2D\u5151\u6362\u7801\u624B\u52A8\u590D\u5236\uFF0C\u6216\u4F7F\u7528\u4E0B\u65B9\u300C\u4E0B\u8F7D TXT\u300D\u3002"})]})}async function Lo(e,t){let{ok:o,data:r}=await KM(e,t);if(!o)throw new Error(r.message||"\u8BF7\u6C42\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u91CD\u8BD5\u3002");return r}function p3(){return Lo("/api/admin/stats")}function yl(e){let t=new Date(e*1e3),o=r=>String(r).padStart(2,"0");return`${t.getFullYear()}-${o(t.getMonth()+1)}-${o(t.getDate())} ${o(t.getHours())}:${o(t.getMinutes())}:${o(t.getSeconds())}`}var ts={active:{label:"\u53EF\u4F7F\u7528",color:"primary"},processing:{label:"\u5904\u7406\u4E2D",color:"primary"},succeeded:{label:"\u5DF2\u5B8C\u6210",color:"success"},review:{label:"\u5F85\u6838\u5B9E",color:"warning"},revoked:{label:"\u5DF2\u505C\u7528",color:"default"}};var id=C(I(),1);var c3=C(z(),1),u3=ie((0,c3.jsx)("path",{d:"m9.17 6 2 2H20v10H4V6zM10 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2h-8z"}),"FolderOutlined");var f3=C(z(),1),d3=ie((0,f3.jsx)("path",{d:"m14.06 9.02.92.92L5.92 19H5v-.92zM17.66 3c-.25 0-.51.1-.7.29l-1.83 1.83 3.75 3.75 1.83-1.83c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.2-.2-.45-.29-.71-.29m-3.6 3.19L3 17.25V21h3.75L17.81 9.94z"}),"EditOutlined");var Nt=C(z(),1);function m3({folders:e,stats:t,filter:o,disabled:r,onSelect:n,onBusyChange:a,onChanged:i}){let[s,l]=(0,id.useState)(null),[p,c]=(0,id.useState)(""),[d,f]=(0,id.useState)(""),[u,g]=(0,id.useState)(!1);async function x(){if(!(!s||u)){if(!p.trim()||new TextEncoder().encode(p.trim()).length>120){f("\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A\uFF0C\u6700\u591A 120 \u5B57\u8282\u3002");return}g(!0),a(!0);try{await Lo("/api/admin/folders/rename",{id:s.id,name:p.trim()}),await i(),l(null)}catch(v){f(v.message)}finally{g(!1),a(!1)}}}return(0,Nt.jsxs)(ue,{sx:{mb:3},children:[(0,Nt.jsxs)(ve,{direction:"row",justifyContent:"space-between",alignItems:"baseline",sx:{mb:1.5},children:[(0,Nt.jsx)(V,{variant:"h2",children:"\u6279\u6B21"}),(0,Nt.jsxs)(V,{variant:"body2",color:"text.secondary",children:[t?.total??"\u2014"," \u679A\u5151\u6362\u7801"]})]}),(0,Nt.jsx)(V,{variant:"body2",color:"text.secondary",sx:{mb:2},children:"\u70B9\u51FB\u6279\u6B21\u6587\u4EF6\u5939\u67E5\u770B\u5151\u6362\u7801\uFF0C\u5DE6\u53F3\u6ED1\u52A8\u53EF\u67E5\u770B\u5168\u90E8\u6279\u6B21\u3002"}),(0,Nt.jsx)(ve,{direction:"row",useFlexGap:!0,gap:1,sx:{minHeight:80,overflowX:"auto",alignItems:"center",pb:1},role:"region","aria-label":"\u6279\u6B21\u6587\u4EF6\u5939\uFF0C\u53EF\u6A2A\u5411\u6EDA\u52A8",tabIndex:0,children:[{id:"",name:"\u5168\u90E8\u5151\u6362\u7801",count:t?.total??0},...t?.unfiled?[{id:"unfiled",name:"\u672A\u5206\u7C7B",count:t.unfiled}]:[],...e].map(v=>(0,Nt.jsxs)(ue,{sx:{display:"flex",border:1,borderColor:o===v.id?"primary.main":"divider",borderRadius:2,bgcolor:o===v.id?"action.selected":"background.paper",maxWidth:"100%",flexShrink:0},children:[(0,Nt.jsxs)(be,{disabled:r,"aria-pressed":o===v.id,startIcon:(0,Nt.jsx)(u3,{}),onClick:()=>n(v.id),sx:{px:2,py:1.5,justifyContent:"flex-start",textAlign:"left",overflowWrap:"anywhere",minWidth:0},children:[v.name," \xB7 ",v.count]}),v.id&&v.id!=="unfiled"&&(0,Nt.jsx)(_n,{describeChild:!0,title:`\u91CD\u547D\u540D\u6279\u6B21\uFF1A${v.name}`,children:(0,Nt.jsx)("span",{children:(0,Nt.jsx)(Qr,{"aria-label":`\u91CD\u547D\u540D\u6279\u6B21\uFF1A${v.name}`,disabled:
Line truncated
|
||||
`)+`
|
||||
`],{type:"text/plain;charset=utf-8"})),te=document.createElement("a");te.href=Q,te.download=`xgift-${oe.months}mo-${Date.now()}.txt`,te.click(),setTimeout(()=>URL.revokeObjectURL(Q),1e3)}let To=k&&re?re.filter(k.match):null,$r=To?.length??0,mn=Math.max(1,Math.ceil($r/100)),br=Math.min(me,mn-1),nr=To?To.slice(br*100,br*100+100):n?.codes??[];return(0,B.jsxs)(FM,{admin:!0,children:[(0,B.jsxs)(Ce,{direction:{xs:"column",sm:"row"},justifyContent:"space-between",alignItems:{xs:"start",sm:"center"},spacing:2,sx:{mb:4},children:[(0,B.jsxs)(he,{children:[(0,B.jsx)(K,{variant:"h1",sx:{fontSize:{xs:30,sm:36},mt:.5},children:"\u5151\u6362\u7801\u7BA1\u7406"}),(0,B.jsx)(K,{color:"text.secondary",sx:{mt:1},children:"\u751F\u6210\u5151\u6362\u7801\u3001\u67E5\u770B\u5151\u6362\u72B6\u6001\u548C\u7BA1\u7406\u6279\u6B21\u3002"})]}),(0,B.jsxs)(Ce,{direction:"row",alignItems:"center",spacing:1,children:[(0,B.jsx)(Nr,{variant:"outlined",color:n?.payments_enabled?"success":"default",label:n?n.payments_enabled?"\u5145\u503C\u5DF2\u5F00\u653E":"\u7528\u6237\u5145\u503C\u5165\u53E3\u5DF2\u6682\u505C":"\u6B63\u5728\u83B7\u53D6\u670D\u52A1\u72B6\u6001"}),(0,B.jsx)(QM,{})]})]}),(0,B.jsx)(PA,{selected:e,onPrepare:(Q,te)=>r({id:Q,mode:te,seq:Date.now()})}),(0,B.jsx)(OA,{selection:o}),(0,B.jsx)(MA,{refreshSignal:ke}),(0,B.jsx)(sA,{folders:n?.folders??[],stats:n?.stats,filter:n?.folder??"",disabled:c||i,muted:!!k,onSelect:Q=>{if(k){je(!1);let te=Q==="unfiled"?"\u672A\u5206\u7C7B":Q?n?.folders.find(ve=>ve.id===Q)?.name??"":"";te&&le(ve=>({seq:ve.seq+1,text:`\u7B5B\u9009\u5DF2\u6E05\u9664\uFF0C\u5DF2\u663E\u793A\u6279\u6B21\uFF1A${te}`}))}Bt(0,Q)},onBusyChange:Q=>{Ne.current=Q,m(Q)},onChanged:async Q=>{Q===N.current&&(N.current=""),k?Ke():await Bt(0)}}),k&&(0,B.jsx)(K,{variant:"body2",color:"text.secondary",sx:{mt:-1.5,mb:3},children:"\u8868\u8FBE\u5F0F\u7B5B\u9009\u751F\u6548\u4E2D\uFF0C\u70B9\u51FB\u6279\u6B21\u6587\u4EF6\u5939\u53EF\u6E05\u9664\u7B5B\u9009\u5E76\u67E5\u770B\u8BE5\u6279\u6B21\u3002"}),(0,B.jsx)(xA,{value:b,onChange:Q=>{M(Q),A&&_("")},onApply:()=>{b.trim()&&Ye(b.trim())},onClear:()=>je(),applied:!!k,error:A,disabled:c||i,folders:n?.folders??[],appliedSource:k?.source??"",resultCount:k?$r:void 0,applySeq:ue,clearNotice:Ee}),(0,B.jsxs)(xt,{variant:"outlined",sx:{p:{xs:2.5,sm:3},mb:3},children:[(0,B.jsxs)(Ce,{direction:"row",spacing:1,alignItems:"center",sx:{mb:1},children:[(0,B.jsx)(Vb,{color:"primary"}),(0,B.jsx)(K,{variant:"h2",children:"\u751F\u6210\u5151\u6362\u7801"})]}),(0,B.jsx)(K,{variant:"body2",color:"text.secondary",sx:{mb:3},children:"\u6BCF\u6279\u6700\u591A 500 \u679A\u3002\u540C\u540D\u6279\u6B21\u81EA\u52A8\u5F52\u5165\u540C\u4E00\u4E2A\u6587\u4EF6\u5939\u3002"}),(0,B.jsx)(he,{component:"form",ref:pe,noValidate:!0,onSubmit:Q=>{Q.preventDefault();let te=new TextEncoder().encode(x.trim()).length>120,ve=!Number.isInteger(Number(g))||Number(g)<1||Number(g)>500;$(te),xe(ve),!(te||ve||!pe.current.reportValidity()||c)&&rr()},children:(0,B.jsxs)(he,{sx:{display:"grid",gridTemplateColumns:{xs:"1fr",sm:"1fr 1fr",md:"1fr 1fr 2fr"},gap:2,alignItems:"start"},children:[(0,B.jsxs)(Io,{select:!0,label:"\u5957\u9910\u65F6\u957F",value:f,onChange:Q=>u(Number(Q.target.value)),disabled:c,helperText:"\u7ED1\u5B9A\u540E\u4E0D\u53EF\u66F4\u6539",children:[(0,B.jsx)(_a,{value:3,children:"3 \u4E2A\u6708 Premium"}),(0,B.jsx)(_a,{value:6,children:"6 \u4E2A\u6708 Premium"})]}),(0,B.jsx)(Io,{label:"\u751F\u6210\u6570\u91CF",type:"number",required:!0,value:g,onChange:Q=>v(Q.target.value),disabled:c,error:z,helperText:z?"\u8BF7\u8F93\u5165 1\u2013500 \u4E4B\u95F4\u7684\u6574\u6570":"\u6BCF\u6279 1\u2013500 \u679A",slotProps:{htmlInput:{min:1,max:500,step:1}}}),(0,B.jsx)(Io,{label:"\u6279\u6B21\u540D\u79F0\uFF08\u53EF\u9009\uFF09",placeholder:"\u4F8B\u5982\uFF1A\u5341\u6708\u8D60\u793C",value:x,onChange:Q=>d(Q.target.value),disabled:c,error:be,helperText:be?"\u6279\u6B21\u540D\u79F0\u4E0D\u80FD\u8D85\u8FC7 120 \u5B57\u8282\uFF08\u7EA6 40 \u4E2A\u6C49\u5B57\uFF09":"\u6279\u6B21\u540D\u79F0\u5C31\u662F\u6587\u4EF6\u5939\u540D\u79F0\uFF0C\u7559\u7A7A\u81EA\u52A8\u547D\u540D"}),(0,B.jsx)(Se,{type:"submit",variant:"contained",startIcon:(0,B.jsx)(M2,{}),disabled:c||i||!!l,sx:{gridColumn:{sm:"1 / -1"},justifySelf:{sm:"end"}},children:c?"\u6B63\u5728\u5904\u7406\u2026":"\u751F\u6210\u5151\u6362\u7801"})]})})]}),ge&&(0,B.jsx)(gt,{severity:ge.error?"error":"success",role:"status",sx:{mb:3},children:ge.text}),oe&&(0,B.jsxs)(xt,{ref:ao,variant:"outlined",sx:{p:3,mb:3,borderColor:"primary.main"},children:[(0,B.jsx)(K,{variant:"h2",children:"\u672C\u6279\u5151\u6362\u7801"}),(0,B.jsxs)(K,{variant:"body2",color:"text.secondary",sx:{my:1,overflowWrap:"anywhere"},children:[oe.batch," \xB7 ",oe.codes.length," \u679A \xB7 ",oe.months," ","\u4E2A\u6708"]}),(0,B.jsx)(tA,{codes:oe.codes},oe.codes[0]),(0,B.jsxs)(Ce,{direction:{xs:"column",sm:"row"},spacing:1.5,children:[(0,B.jsx)(Se,{variant:"contained",startIcon:(0,B.jsx)(D2,{}),onClick:Ut,children:"\u4E0B\u8F
Line truncated
|
||||
`],{type:"text/plain;charset=utf-8"})),je=document.createElement("a");je.href=X,je.download=`xgift-${he.months}mo-${Date.now()}.txt`,je.click(),setTimeout(()=>URL.revokeObjectURL(X),1e3)}let lr=ee&&ye?ye.filter(ee.match):null,ma=lr?.length??0,Fn=Math.max(1,Math.ceil(ma/100)),Vr=Math.min(ce,Fn-1),de=lr?lr.slice(Vr*100,Vr*100+100):n?.codes??[],ze=de.map(X=>X.id),Mt=ze.filter(X=>E.includes(X));return(0,j.jsxs)(QM,{admin:!0,children:[(0,j.jsxs)(ve,{direction:{xs:"column",sm:"row"},justifyContent:"space-between",alignItems:{xs:"start",sm:"center"},spacing:2,sx:{mb:4},children:[(0,j.jsxs)(ue,{children:[(0,j.jsx)(V,{variant:"h1",sx:{fontSize:{xs:30,sm:36},mt:.5},children:"\u5151\u6362\u7801\u7BA1\u7406"}),(0,j.jsx)(V,{color:"text.secondary",sx:{mt:1},children:"\u751F\u6210\u5151\u6362\u7801\u3001\u67E5\u770B\u5151\u6362\u72B6\u6001\u548C\u7BA1\u7406\u6279\u6B21\u3002"})]}),(0,j.jsxs)(ve,{direction:"row",alignItems:"center",spacing:1,children:[(0,j.jsx)(er,{variant:"outlined",color:n?.payments_enabled?"success":"default",label:n?n.payments_enabled?"\u5145\u503C\u5DF2\u5F00\u653E":"\u7528\u6237\u5145\u503C\u5165\u53E3\u5DF2\u6682\u505C":"\u6B63\u5728\u83B7\u53D6\u670D\u52A1\u72B6\u6001"}),(0,j.jsx)(n3,{})]})]}),(0,j.jsxs)(ue,{sx:{display:"grid",gridTemplateColumns:{xs:"1fr",md:"minmax(0, 1fr) minmax(0, 1fr)"},gap:3,mb:3,alignItems:"stretch"},children:[(0,j.jsx)(M3,{selected:e,onPrepare:(X,je)=>r({id:X,mode:je,seq:Date.now()})}),(0,j.jsx)(D3,{disabled:c||i,refreshSignal:Ze,onCopy:X=>{we(X)},onViewCustomer:X=>t({id:X,seq:Date.now()}),onRevoke:X=>$({kind:"revoke",code:X})})]}),(0,j.jsx)(U3,{selection:o}),(0,j.jsx)(H3,{refreshSignal:Ze}),(0,j.jsx)(m3,{folders:n?.folders??[],stats:n?.stats,filter:n?.folder??"",disabled:c||i,onSelect:X=>{if(ee){ot(!1);let je=X==="unfiled"?"\u672A\u5206\u7C7B":X?n?.folders.find(At=>At.id===X)?.name??"":"";je&&Te(At=>({seq:At.seq+1,text:`\u7B5B\u9009\u5DF2\u6E05\u9664\uFF0C\u5DF2\u663E\u793A\u6279\u6B21\uFF1A${je}`}))}Ae(0,X)},onBusyChange:X=>{gt.current=X,d(X)},onChanged:async()=>{ee?oo():await Ae(0)}}),ee&&(0,j.jsx)(V,{variant:"body2",color:"text.secondary",sx:{mt:-1.5,mb:3},children:"\u8868\u8FBE\u5F0F\u7B5B\u9009\u751F\u6548\u4E2D\uFF0C\u70B9\u51FB\u6279\u6B21\u6587\u4EF6\u5939\u53EF\u6E05\u9664\u7B5B\u9009\u5E76\u67E5\u770B\u8BE5\u6279\u6B21\u3002"}),(0,j.jsx)(w3,{value:M,onChange:X=>{_(X),D&&K("")},onApply:()=>{M.trim()&<(M.trim())},onClear:()=>ot(),applied:!!ee,error:D,disabled:c||i,folders:n?.folders??[],appliedSource:ee?.source??"",resultCount:ee?ma:void 0,applySeq:Ce,clearNotice:re}),(0,j.jsxs)(dt,{variant:"outlined",sx:{p:{xs:2.5,sm:3},mb:3},children:[(0,j.jsxs)(ve,{direction:"row",spacing:1,alignItems:"center",sx:{mb:1},children:[(0,j.jsx)(Xb,{color:"primary"}),(0,j.jsx)(V,{variant:"h2",children:"\u751F\u6210\u5151\u6362\u7801"})]}),(0,j.jsx)(V,{variant:"body2",color:"text.secondary",sx:{mb:3},children:"\u6BCF\u6279\u6700\u591A 500 \u679A\u3002\u540C\u540D\u6279\u6B21\u81EA\u52A8\u5F52\u5165\u540C\u4E00\u4E2A\u6587\u4EF6\u5939\u3002"}),(0,j.jsx)(ue,{component:"form",ref:Tt,noValidate:!0,onSubmit:X=>{X.preventDefault();let je=new TextEncoder().encode(v.trim()).length>120,At=!Number.isInteger(Number(g))||Number(g)<1||Number(g)>500;Pe(je),Se(At),!(je||At||!Tt.current.reportValidity()||c)&&Co()},children:(0,j.jsxs)(ue,{sx:{display:"grid",gridTemplateColumns:{xs:"1fr",sm:"1fr 1fr",md:"1fr 1fr 2fr"},gap:2,alignItems:"start"},children:[(0,j.jsxs)(To,{select:!0,label:"\u5957\u9910\u65F6\u957F",value:f,onChange:X=>u(Number(X.target.value)),disabled:c,helperText:"\u7ED1\u5B9A\u540E\u4E0D\u53EF\u66F4\u6539",children:[(0,j.jsx)(Ua,{value:3,children:"3 \u4E2A\u6708 Premium"}),(0,j.jsx)(Ua,{value:6,children:"6 \u4E2A\u6708 Premium"})]}),(0,j.jsx)(To,{label:"\u751F\u6210\u6570\u91CF",type:"number",required:!0,value:g,onChange:X=>{x(X.target.value),Me&&Se(!1)},disabled:c,error:Me,helperText:Me?"\u8BF7\u8F93\u5165 1\u2013500 \u4E4B\u95F4\u7684\u6574\u6570":"\u6BCF\u6279 1\u2013500 \u679A",slotProps:{htmlInput:{min:1,max:500,step:1}}}),(0,j.jsx)(To,{label:"\u6279\u6B21\u540D\u79F0\uFF08\u53EF\u9009\uFF09",placeholder:"\u4F8B\u5982\uFF1A\u5341\u6708\u8D60\u793C",value:v,onChange:X=>{m(X.target.value),U&&Pe(!1)},disabled:c,error:U,helperText:U?"\u6279\u6B21\u540D\u79F0\u4E0D\u80FD\u8D85\u8FC7 120 \u5B57\u8282\uFF08\u7EA6 40 \u4E2A\u6C49\u5B57\uFF09":"\u6279\u6B21\u540D\u79F0\u5C31\u662F\u6587\u4EF6\u5939\u540D\u79F0\uFF0C\u7559\u7A7A\u81EA\u52A8\u547D\u540D"}),(0,j.jsx)(be,{type:"submit",variant:"contained",startIcon:(0,j.jsx)(B2,{}),disabled:c||i||!!l,sx:{gridColumn:{sm:"1 / -1"},justifySelf:{sm:"end"}},children:c?"\u6B63\u5728\u5904\u7406\u2026":"\u751F\u6210\u5151\u6362\u7801"})]})})]}),le&&(0,j.jsx)(pt,{severity:le.error?"error":"success",role:"status",closeText:"\u5173\u95ED",onClose:le.error?void 0:()=>fe(null),sx:{mb:3},children:le.text}),he&&(0,j.jsxs)(dt,{ref:sr,variant:"outlined",sx:{p:3,mb:3,borderColor:"primary.main"},children:[(0,j.jsx)(V,{variant:"h2",children:"\u672C\u6279\u5151\uLine truncated
|
||||
/*! Bundled license information:
|
||||
|
||||
react/cjs/react.production.js:
|
||||
|
||||
Binary file not shown.
+40
-40
@@ -1,15 +1,15 @@
|
||||
var IN=Object.create;var Lb=Object.defineProperty;var VN=Object.getOwnPropertyDescriptor;var HN=Object.getOwnPropertyNames;var FN=Object.getPrototypeOf,$N=Object.prototype.hasOwnProperty;var ro=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(o){throw t=0,o}};var qN=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of HN(t))!$N.call(e,n)&&n!==o&&Lb(e,n,{get:()=>t[n],enumerable:!(r=VN(t,n))||r.enumerable});return e};var C=(e,t,o)=>(o=e!=null?IN(FN(e)):{},qN(t||!e||!e.__esModule?Lb(o,"default",{value:e,enumerable:!0}):o,e));var Zb=ro(ae=>{"use strict";var Ey=Symbol.for("react.transitional.element"),GN=Symbol.for("react.portal"),YN=Symbol.for("react.fragment"),XN=Symbol.for("react.strict_mode"),KN=Symbol.for("react.profiler"),QN=Symbol.for("react.consumer"),ZN=Symbol.for("react.context"),WN=Symbol.for("react.forward_ref"),JN=Symbol.for("react.suspense"),e5=Symbol.for("react.memo"),Fb=Symbol.for("react.lazy"),t5=Symbol.for("react.activity"),o5=Symbol.for("react.view_transition"),kb=Symbol.iterator;function r5(e){return e===null||typeof e!="object"?null:(e=kb&&e[kb]||e["@@iterator"],typeof e=="function"?e:null)}var $b={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},qb=Object.assign,Gb={};function Xi(e,t,o){this.props=e,this.context=t,this.refs=Gb,this.updater=o||$b}Xi.prototype.isReactComponent={};Xi.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Xi.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function Yb(){}Yb.prototype=Xi.prototype;function Ry(e,t,o){this.props=e,this.context=t,this.refs=Gb,this.updater=o||$b}var Oy=Ry.prototype=new Yb;Oy.constructor=Ry;qb(Oy,Xi.prototype);Oy.isPureReactComponent=!0;var Ib=Array.isArray;function Cy(){}var Ye={H:null,A:null,T:null,S:null},Xb=Object.prototype.hasOwnProperty;function Ny(e,t,o){var r=o.ref;return{$$typeof:Ey,type:e,key:t,ref:r!==void 0?r:null,props:o}}function n5(e,t){return Ny(e.type,t,e.props)}function wy(e){return typeof e=="object"&&e!==null&&e.$$typeof===Ey}function a5(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(o){return t[o]})}var Vb=/\/+/g;function Py(e,t){return typeof e=="object"&&e!==null&&e.key!=null?a5(""+e.key):t.toString(36)}function i5(e){switch(e.status){case"fulfilled":return e.value;case"rejected":throw e.reason;default:switch(typeof e.status=="string"?e.then(Cy,Cy):(e.status="pending",e.then(function(t){e.status==="pending"&&(e.status="fulfilled",e.value=t)},function(t){e.status==="pending"&&(e.status="rejected",e.reason=t)})),e.status){case"fulfilled":return e.value;case"rejected":throw e.reason}}throw e}function Yi(e,t,o,r,n){var a=typeof e;(a==="undefined"||a==="boolean")&&(e=null);var i=!1;if(e===null)i=!0;else switch(a){case"bigint":case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case Ey:case GN:i=!0;break;case Fb:return i=e._init,Yi(i(e._payload),t,o,r,n)}}if(i)return n=n(e),i=r===""?"."+Py(e,0):r,Ib(n)?(o="",i!=null&&(o=i.replace(Vb,"$&/")+"/"),Yi(n,t,o,"",function(p){return p})):n!=null&&(wy(n)&&(n=n5(n,o+(n.key==null||e&&e.key===n.key?"":(""+n.key).replace(Vb,"$&/")+"/")+i)),t.push(n)),1;i=0;var s=r===""?".":r+":";if(Ib(e))for(var l=0;l<e.length;l++)r=e[l],a=s+Py(r,l),i+=Yi(r,t,o,a,n);else if(l=r5(e),typeof l=="function")for(e=l.call(e),l=0;!(r=e.next()).done;)r=r.value,a=s+Py(r,l++),i+=Yi(r,t,o,a,n);else if(a==="object"){if(typeof e.then=="function")return Yi(i5(e),t,o,r,n);throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.")}return i}function mc(e,t,o){if(e==null)return e;var r=[],n=0;return Yi(e,r,"","",function(a){return t.call(o,a,n++)}),r}function s5(e){if(e._status===-1){var t=e._result,o=t();o.then(function(r){(e._status===0||e._status===-1)&&(e._status=1,e._result=r,o.status===void 0&&(o.status="fulfilled",o.value=r))},function(r){(e._status===0||e._status===-1)&&(e._status=2,e._result=r,o.status===void 0&&(o.status="rejected",o.reason=r))}),e._status===-1&&(e._status=0,e._result=o)}if(e._status===1)return e._result.default;throw e._result}var Hb=typeof reportError=="function"?reportError:function(e){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof e=="object"&&e!==null&&typeof e.message=="string"?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",e);return}console.error(e)};function Kb(e){var t=Ye.T,o={};o.types=t!==null?t.types:nullLine truncated
|
||||
var FN=Object.create;var Ib=Object.defineProperty;var $N=Object.getOwnPropertyDescriptor;var qN=Object.getOwnPropertyNames;var GN=Object.getPrototypeOf,YN=Object.prototype.hasOwnProperty;var ro=(e,t)=>()=>{try{return t||e((t={exports:{}}).exports,t),t.exports}catch(o){throw t=0,o}};var XN=(e,t,o,r)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of qN(t))!YN.call(e,n)&&n!==o&&Ib(e,n,{get:()=>t[n],enumerable:!(r=$N(t,n))||r.enumerable});return e};var C=(e,t,o)=>(o=e!=null?FN(GN(e)):{},XN(t||!e||!e.__esModule?Ib(o,"default",{value:e,enumerable:!0}):o,e));var Jb=ro(ae=>{"use strict";var Oy=Symbol.for("react.transitional.element"),KN=Symbol.for("react.portal"),QN=Symbol.for("react.fragment"),ZN=Symbol.for("react.strict_mode"),WN=Symbol.for("react.profiler"),JN=Symbol.for("react.consumer"),e5=Symbol.for("react.context"),t5=Symbol.for("react.forward_ref"),o5=Symbol.for("react.suspense"),r5=Symbol.for("react.memo"),qb=Symbol.for("react.lazy"),n5=Symbol.for("react.activity"),a5=Symbol.for("react.view_transition"),Vb=Symbol.iterator;function i5(e){return e===null||typeof e!="object"?null:(e=Vb&&e[Vb]||e["@@iterator"],typeof e=="function"?e:null)}var Gb={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Yb=Object.assign,Xb={};function Zi(e,t,o){this.props=e,this.context=t,this.refs=Xb,this.updater=o||Gb}Zi.prototype.isReactComponent={};Zi.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Zi.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function Kb(){}Kb.prototype=Zi.prototype;function Ny(e,t,o){this.props=e,this.context=t,this.refs=Xb,this.updater=o||Gb}var wy=Ny.prototype=new Kb;wy.constructor=Ny;Yb(wy,Zi.prototype);wy.isPureReactComponent=!0;var Hb=Array.isArray;function Ry(){}var Ke={H:null,A:null,T:null,S:null},Qb=Object.prototype.hasOwnProperty;function Ay(e,t,o){var r=o.ref;return{$$typeof:Oy,type:e,key:t,ref:r!==void 0?r:null,props:o}}function s5(e,t){return Ay(e.type,t,e.props)}function My(e){return typeof e=="object"&&e!==null&&e.$$typeof===Oy}function l5(e){var t={"=":"=0",":":"=2"};return"$"+e.replace(/[=:]/g,function(o){return t[o]})}var Fb=/\/+/g;function Ey(e,t){return typeof e=="object"&&e!==null&&e.key!=null?l5(""+e.key):t.toString(36)}function p5(e){switch(e.status){case"fulfilled":return e.value;case"rejected":throw e.reason;default:switch(typeof e.status=="string"?e.then(Ry,Ry):(e.status="pending",e.then(function(t){e.status==="pending"&&(e.status="fulfilled",e.value=t)},function(t){e.status==="pending"&&(e.status="rejected",e.reason=t)})),e.status){case"fulfilled":return e.value;case"rejected":throw e.reason}}throw e}function Qi(e,t,o,r,n){var a=typeof e;(a==="undefined"||a==="boolean")&&(e=null);var i=!1;if(e===null)i=!0;else switch(a){case"bigint":case"string":case"number":i=!0;break;case"object":switch(e.$$typeof){case Oy:case KN:i=!0;break;case qb:return i=e._init,Qi(i(e._payload),t,o,r,n)}}if(i)return n=n(e),i=r===""?"."+Ey(e,0):r,Hb(n)?(o="",i!=null&&(o=i.replace(Fb,"$&/")+"/"),Qi(n,t,o,"",function(p){return p})):n!=null&&(My(n)&&(n=s5(n,o+(n.key==null||e&&e.key===n.key?"":(""+n.key).replace(Fb,"$&/")+"/")+i)),t.push(n)),1;i=0;var s=r===""?".":r+":";if(Hb(e))for(var l=0;l<e.length;l++)r=e[l],a=s+Ey(r,l),i+=Qi(r,t,o,a,n);else if(l=i5(e),typeof l=="function")for(e=l.call(e),l=0;!(r=e.next()).done;)r=r.value,a=s+Ey(r,l++),i+=Qi(r,t,o,a,n);else if(a==="object"){if(typeof e.then=="function")return Qi(p5(e),t,o,r,n);throw t=String(e),Error("Objects are not valid as a React child (found: "+(t==="[object Object]"?"object with keys {"+Object.keys(e).join(", ")+"}":t)+"). If you meant to render a collection of children, use an array instead.")}return i}function Tc(e,t,o){if(e==null)return e;var r=[],n=0;return Qi(e,r,"","",function(a){return t.call(o,a,n++)}),r}function u5(e){if(e._status===-1){var t=e._result,o=t();o.then(function(r){(e._status===0||e._status===-1)&&(e._status=1,e._result=r,o.status===void 0&&(o.status="fulfilled",o.value=r))},function(r){(e._status===0||e._status===-1)&&(e._status=2,e._result=r,o.status===void 0&&(o.status="rejected",o.reason=r))}),e._status===-1&&(e._status=0,e._result=o)}if(e._status===1)return e._result.default;throw e._result}var $b=typeof reportError=="function"?reportError:function(e){if(typeof window=="object"&&typeof window.ErrorEvent=="function"){var t=new window.ErrorEvent("error",{bubbles:!0,cancelable:!0,message:typeof e=="object"&&e!==null&&typeof e.message=="string"?String(e.message):String(e),error:e});if(!window.dispatchEvent(t))return}else if(typeof process=="object"&&typeof process.emit=="function"){process.emit("uncaughtException",e);return}console.error(e)};function Zb(e){var t=Ke.T,o={};o.types=t!==null?t.types:nullLine truncated
|
||||
at`)?" (<anonymous>)":-1<o.stack.indexOf("@")?"@unknown:0:0":""}return`
|
||||
`+Gg+e+IC}var Yg=!1;function Xg(e,t){if(!e||Yg)return"";Yg=!0;var o=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var r={DetermineComponentFrameRoot:function(){try{if(t){var d=function(){throw Error()};if(Object.defineProperty(d.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(d,[])}catch(b){var c=b}Reflect.construct(e,[],d)}else{try{d.call()}catch(b){c=b}d=!1;try{var u=Object.getOwnPropertyDescriptor(e.prototype,"props");Object.defineProperty(e.prototype,"props",{configurable:!0,set:function(){throw Error()}}),d=!0,new e}finally{d&&(u!==void 0?Object.defineProperty(e.prototype,"props",u):delete e.prototype.props)}}}else{try{throw Error()}catch(b){c=b}(d=e())&&typeof d.catch=="function"&&d.catch(function(){})}}catch(b){if(b&&c&&typeof b.stack=="string")return[b.stack,c.stack]}return[null,null]}};r.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var n=Object.getOwnPropertyDescriptor(r.DetermineComponentFrameRoot,"name");n&&n.configurable&&Object.defineProperty(r.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var a=r.DetermineComponentFrameRoot(),i=a[0],s=a[1];if(i&&s){var l=i.split(`
|
||||
`+Xg+e+IC}var Kg=!1;function Qg(e,t){if(!e||Kg)return"";Kg=!0;var o=Error.prepareStackTrace;Error.prepareStackTrace=void 0;try{var r={DetermineComponentFrameRoot:function(){try{if(t){var d=function(){throw Error()};if(Object.defineProperty(d.prototype,"props",{set:function(){throw Error()}}),typeof Reflect=="object"&&Reflect.construct){try{Reflect.construct(d,[])}catch(b){var c=b}Reflect.construct(e,[],d)}else{try{d.call()}catch(b){c=b}d=!1;try{var u=Object.getOwnPropertyDescriptor(e.prototype,"props");Object.defineProperty(e.prototype,"props",{configurable:!0,set:function(){throw Error()}}),d=!0,new e}finally{d&&(u!==void 0?Object.defineProperty(e.prototype,"props",u):delete e.prototype.props)}}}else{try{throw Error()}catch(b){c=b}(d=e())&&typeof d.catch=="function"&&d.catch(function(){})}}catch(b){if(b&&c&&typeof b.stack=="string")return[b.stack,c.stack]}return[null,null]}};r.DetermineComponentFrameRoot.displayName="DetermineComponentFrameRoot";var n=Object.getOwnPropertyDescriptor(r.DetermineComponentFrameRoot,"name");n&&n.configurable&&Object.defineProperty(r.DetermineComponentFrameRoot,"name",{value:"DetermineComponentFrameRoot"});var a=r.DetermineComponentFrameRoot(),i=a[0],s=a[1];if(i&&s){var l=i.split(`
|
||||
`),p=s.split(`
|
||||
`);for(n=r=0;r<l.length&&!l[r].includes("DetermineComponentFrameRoot");)r++;for(;n<p.length&&!p[n].includes("DetermineComponentFrameRoot");)n++;if(r===l.length||n===p.length)for(r=l.length-1,n=p.length-1;1<=r&&0<=n&&l[r]!==p[n];)n--;for(;1<=r&&0<=n;r--,n--)if(l[r]!==p[n]){if(r!==1||n!==1)do if(r--,n--,0>n||l[r]!==p[n]){var f=`
|
||||
`+l[r].replace(" at new "," at ");return e.displayName&&f.includes("<anonymous>")&&(f=f.replace("<anonymous>",e.displayName)),f}while(1<=r&&0<=n);break}}}finally{Yg=!1,Error.prepareStackTrace=o}return(o=e?e.displayName||e.name:"")?pa(o):""}function Qz(e,t){switch(e.tag){case 26:case 27:case 5:return pa(e.type);case 16:return pa("Lazy");case 13:return e.child!==t&&t!==null?pa("Suspense Fallback"):pa("Suspense");case 19:return pa("SuspenseList");case 0:case 15:return Xg(e.type,!1);case 11:return Xg(e.type.render,!1);case 1:return Xg(e.type,!0);case 31:return pa("Activity");case 30:return pa("ViewTransition");default:return""}}function VC(e){try{var t="",o=null;do t+=Qz(e,o),o=e,e=e.return;while(e);return t}catch(r){return`
|
||||
`+l[r].replace(" at new "," at ");return e.displayName&&f.includes("<anonymous>")&&(f=f.replace("<anonymous>",e.displayName)),f}while(1<=r&&0<=n);break}}}finally{Kg=!1,Error.prepareStackTrace=o}return(o=e?e.displayName||e.name:"")?fa(o):""}function Jz(e,t){switch(e.tag){case 26:case 27:case 5:return fa(e.type);case 16:return fa("Lazy");case 13:return e.child!==t&&t!==null?fa("Suspense Fallback"):fa("Suspense");case 19:return fa("SuspenseList");case 0:case 15:return Qg(e.type,!1);case 11:return Qg(e.type.render,!1);case 1:return Qg(e.type,!0);case 31:return fa("Activity");case 30:return fa("ViewTransition");default:return""}}function VC(e){try{var t="",o=null;do t+=Jz(e,o),o=e,e=e.return;while(e);return t}catch(r){return`
|
||||
Error generating stack: `+r.message+`
|
||||
`+r.stack}}var DT=Object.prototype.hasOwnProperty,U0=Rt.unstable_scheduleCallback,Kg=Rt.unstable_cancelCallback,Zz=Rt.unstable_shouldYield,Wz=Rt.unstable_requestPaint,Fo=Rt.unstable_now,Jz=Rt.unstable_getCurrentPriorityLevel,wR=Rt.unstable_ImmediatePriority,AR=Rt.unstable_UserBlockingPriority,Om=Rt.unstable_NormalPriority,e6=Rt.unstable_LowPriority,MR=Rt.unstable_IdlePriority,t6=Rt.log,o6=Rt.unstable_setDisableYieldValue,tc=null,$o=null;function ma(e){if(typeof t6=="function"&&o6(e),$o&&typeof $o.setStrictMode=="function")try{$o.setStrictMode(tc,e)}catch{}}var qo=Math.clz32?Math.clz32:a6,r6=Math.log,n6=Math.LN2;function a6(e){return e>>>=0,e===0?32:31-(r6(e)/n6|0)|0}var kd=256,Id=262144,Vd=4194304;function xi(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&-e;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Jm(e,t,o){var r=e.pendingLanes;if(r===0)return 0;var n=0,a=e.suspendedLanes,i=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s!==0?(r=s&~a,r!==0?n=xi(r):(i&=s,i!==0?n=xi(i):o||(o=s&~e,o!==0&&(n=xi(o))))):(s=r&~a,s!==0?n=xi(s):i!==0?n=xi(i):o||(o=r&~e,o!==0&&(n=xi(o)))),n===0?0:t!==0&&t!==n&&(t&a)===0&&(a=n&-n,o=t&-t,a>=o||a===32&&(o&4194048)!==0)?t:n}function oc(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function _R(e,t){(t&8)!==0&&(t|=t&32);var o=e.entangledLanes;if(o!==0)for(e=e.entanglements,o&=t;0<o;){var r=31-qo(o),n=1<<r;t|=e[r],o&=~n}return t}function i6(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function DR(){var e=Vd;return Vd<<=1,(Vd&62914560)===0&&(Vd=4194304),e}function Qg(e){for(var t=[],o=0;31>o;o++)t.push(e);return t}function rc(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function s6(e,t,o,r,n,a){var i=e.pendingLanes;e.pendingLanes=o,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=o,e.entangledLanes&=o,e.errorRecoveryDisabledLanes&=o,e.shellSuspendCounter=0;var s=e.entanglements,l=e.expirationTimes,p=e.hiddenUpdates;for(o=i&~o;0<o;){var f=31-qo(o),d=1<<f;s[f]=0,l[f]=-1;var c=p[f];if(c!==null)for(p[f]=null,f=0;f<c.length;f++){var u=c[f];u!==null&&(u.lane&=-536870913)}o&=~d}r!==0&&zR(e,r,0),a!==0&&n===0&&e.tag!==0&&(e.suspendedLanes|=a&~(i&~t))}function zR(e,t,o){e.pendingLanes|=t,e.suspendedLanes&=~t;var r=31-qo(t);e.entangledLanes|=t,e.entanglements[r]=e.entanglements[r]|1073741824|o&261930}function jR(e,t){var o=e.entangledLanes|=t;for(e=e.entanglements;o;){var r=31-qo(o),n=1<<r;n&t|e[r]&t&&(e[r]|=t),o&=~n}}function UR(e,t){var o=t&-t;return o=(o&42)!==0?1:B0(o),(o&(e.suspendedLanes|t))!==0?0:o}function B0(e){switch(e){case 2:e=1;break;case 8:e=4;break;case 32:e=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:e=128;break;case 268435456:e=134217728;break;default:e=0}return e}function L0(e){return e&=-e,2<e?8<e?(e&134217727)!==0?32:268435456:8:2}function BR(){var e=Re.p;return e!==0?e:(e=window.event,e===void 0?32:TN(e.type))}function HC(e,t){var o=Re.p;try{return Re.p=e,t()}finally{Re.p=o}}var jn=Math.random().toString(36).slice(2),Ft="__reactFiber$"+jn,Oo="__reactProps$"+jn,kl="__reactContainer$"+jn,FC="__reactEvents$"+jn,l6="__reactListeners$"+jn,p6="__reactHandles$"+jn,$C="__reactResources$"+jn,nc="__reactMarker$"+jn,Nm="__reactLoad$"+jn;function ey(e){delete e[Ft],delete e[Oo],delete e[l6],delete e[p6]}function Ci(e){var t;if(t=e[Ft])return t;for(var o=e.parentNode;o;){if(t=o[kl]||o[Ft]){if(o=t.alternate,t.child!==null||o!==null&&o.child!==null)for(e=sR(e);e!==null;){if(o=e[Ft])return o;e=sR(e)}return t}e=o,o=e.parentNode}return null}function Il(e){if(e=e[Ft]||e[kl]){var t=e.tag;if(t===5||t===6||t===13||t===31||t===26||t===27||t===3)return e}return null}function Su(e){var t=e.tag;if(t===5||t===26||t===27||t===6)return e.stateNode;throw Error(z(33))}function hl(e){var t=e[$C];return t||(t=e[$C]={hoistableStyles:new Map,hoistableScripts:new Map}),t}function _t(e){e[nc]=!0}function LR(e){e[Nm]=void 0}var kR=new Set,IR={};function Ii(e,t){Ol(e,t),Ol(e+"Capt
Line truncated
|
||||
`).replace(Xj,"")}function K2(e,t){return t=ZE(t),ZE(e)===t}function ke(e,t,o,r,n,a){switch(o){case"children":if(typeof r=="string")t==="body"||t==="textarea"&&r===""||Nl(e,r);else if(typeof r=="number"||typeof r=="bigint")t!=="body"&&Nl(e,""+r);else return;break;case"className":Hd(e,"class",r);break;case"tabIndex":Hd(e,"tabindex",r);break;case"dir":case"role":case"viewBox":case"width":case"height":Hd(e,o,r);break;case"style":GR(e,r,a);return;case"data":if(t!=="object"){Hd(e,"data",r);break}case"src":case"href":if(r===""&&(t!=="a"||o!=="href")){e.removeAttribute(o);break}if(r==null||typeof r=="function"||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=im(r),e.setAttribute(o,r);break;case"action":case"formAction":if(typeof r=="function"){e.setAttribute(o,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof a=="function"&&(o==="formAction"?(t!=="input"&&ke(e,t,"name",n.name,n,null),ke(e,t,"formEncType",n.formEncType,n,null),ke(e,t,"formMethod",n.formMethod,n,null),ke(e,t,"formTarget",n.formTarget,n,null)):(ke(e,t,"encType",n.encType,n,null),ke(e,t,"method",n.method,n,null),ke(e,t,"target",n.target,n,null)));if(r==null||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=im(r),e.setAttribute(o,r);break;case"onClick":r!=null&&(e.onclick=Yr);return;case"onScroll":r!=null&&me("scroll",e);return;case"onScrollEnd":r!=null&&me("scrollend",e);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(z(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(z(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"multiple":e.multiple=r&&typeof r!="function"&&typeof r!="symbol";break;case"muted":e.muted=r&&typeof r!="function"&&typeof r!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(r==null||typeof r=="function"||typeof r=="boolean"||typeof r=="symbol"){e.removeAttribute("xlink:href");break}o=im(r),e.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",o);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"credentialless":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":r&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,""):e.removeAttribute(o);break;case"capture":case"download":r===!0?e.setAttribute(o,""):r!==!1&&r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"cols":case"rows":case"size":case"span":r!=null&&typeof r!="function"&&typeof r!="symbol"&&!isNaN(r)&&1<=r?e.setAttribute(o,r):e.removeAttribute(o);break;case"rowSpan":case"start":r==null||typeof r=="function"||typeof r=="symbol"||isNaN(r)?e.removeAttribute(o):e.setAttribute(o,r);break;case"popover":me("beforetoggle",e),me("toggle",e),am(e,"popover",r);break;case"xlinkActuate":Pn(e,"http://www.w3.org/1999/xlink","xlink:actuate",r);break;case"xlinkArcrole":Pn(e,"http://www.w3.org/1999/xlink","xlink:arcrole",r);break;case"xlinkRole":Pn(e,"http://www.w3.org/1999/xlink","xlink:role",r);break;case"xlinkShow":Pn(e,"http://www.w3.org/1999/xlink","xlink:show",r);break;case"xlinkTitle":Pn(e,"http://www.w3.org/1999/xlink","xlink:title",r);break;case"xlinkType":Pn(e,"http://www.w3.org/1999/xlink","xlink:type",r);break;case"xmlBase":Pn(e,"http://www.w3.org/XML/1998/namespace","xml:base",r);break;case"xmlLang":Pn(e,"http://www.w3.org/XML/1998/namespace","xml:lang",r);break;case"xmlSpace":Pn(e,"http://www.w3.org/XML/1998/namespace","xml:space",r);break;case"is":am(e,"is",r);break;case"innerText":case"textContent":return;default:if(!(2<o.length)||o[0]!=="o"&&o[0]!=="O"||o[1]!=="n"&&o[1]!=="N")o=y6.get(o)||o,am(e,o,r);else return}Ce=!0}function P0(e,t,o,r,n,a){switch(o){case"style":GR(e,r,a);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(z(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(z(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"children":if(typeof r=="string")Nl(e,r);else if(typeof r=="number"||typeof r=="bigint")Nl(e,""+r);else return;break;case"onScroll":r!=null&&me("scroll",e);return;case"onScrollEnd":r!=null&&me("scrollend",e);return;case"onClick":r
Line truncated
|
||||
`+r.stack}}var jT=Object.prototype.hasOwnProperty,L0=Ot.unstable_scheduleCallback,Zg=Ot.unstable_cancelCallback,e6=Ot.unstable_shouldYield,t6=Ot.unstable_requestPaint,$o=Ot.unstable_now,o6=Ot.unstable_getCurrentPriorityLevel,wR=Ot.unstable_ImmediatePriority,AR=Ot.unstable_UserBlockingPriority,Am=Ot.unstable_NormalPriority,r6=Ot.unstable_LowPriority,MR=Ot.unstable_IdlePriority,n6=Ot.log,a6=Ot.unstable_setDisableYieldValue,nc=null,qo=null;function ga(e){if(typeof n6=="function"&&a6(e),qo&&typeof qo.setStrictMode=="function")try{qo.setStrictMode(nc,e)}catch{}}var Go=Math.clz32?Math.clz32:l6,i6=Math.log,s6=Math.LN2;function l6(e){return e>>>=0,e===0?32:31-(i6(e)/s6|0)|0}var Hd=256,Fd=262144,$d=4194304;function Ci(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&-e;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function oy(e,t,o){var r=e.pendingLanes;if(r===0)return 0;var n=0,a=e.suspendedLanes,i=e.pingedLanes;e=e.warmLanes;var s=r&134217727;return s!==0?(r=s&~a,r!==0?n=Ci(r):(i&=s,i!==0?n=Ci(i):o||(o=s&~e,o!==0&&(n=Ci(o))))):(s=r&~a,s!==0?n=Ci(s):i!==0?n=Ci(i):o||(o=r&~e,o!==0&&(n=Ci(o)))),n===0?0:t!==0&&t!==n&&(t&a)===0&&(a=n&-n,o=t&-t,a>=o||a===32&&(o&4194048)!==0)?t:n}function ac(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function _R(e,t){(t&8)!==0&&(t|=t&32);var o=e.entangledLanes;if(o!==0)for(e=e.entanglements,o&=t;0<o;){var r=31-Go(o),n=1<<r;t|=e[r],o&=~n}return t}function p6(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function DR(){var e=$d;return $d<<=1,($d&62914560)===0&&($d=4194304),e}function Wg(e){for(var t=[],o=0;31>o;o++)t.push(e);return t}function ic(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function u6(e,t,o,r,n,a){var i=e.pendingLanes;e.pendingLanes=o,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=o,e.entangledLanes&=o,e.errorRecoveryDisabledLanes&=o,e.shellSuspendCounter=0;var s=e.entanglements,l=e.expirationTimes,p=e.hiddenUpdates;for(o=i&~o;0<o;){var f=31-Go(o),d=1<<f;s[f]=0,l[f]=-1;var c=p[f];if(c!==null)for(p[f]=null,f=0;f<c.length;f++){var u=c[f];u!==null&&(u.lane&=-536870913)}o&=~d}r!==0&&zR(e,r,0),a!==0&&n===0&&e.tag!==0&&(e.suspendedLanes|=a&~(i&~t))}function zR(e,t,o){e.pendingLanes|=t,e.suspendedLanes&=~t;var r=31-Go(t);e.entangledLanes|=t,e.entanglements[r]=e.entanglements[r]|1073741824|o&261930}function jR(e,t){var o=e.entangledLanes|=t;for(e=e.entanglements;o;){var r=31-Go(o),n=1<<r;n&t|e[r]&t&&(e[r]|=t),o&=~n}}function UR(e,t){var o=t&-t;return o=(o&42)!==0?1:k0(o),(o&(e.suspendedLanes|t))!==0?0:o}function k0(e){switch(e){case 2:e=1;break;case 8:e=4;break;case 32:e=16;break;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:case 4194304:case 8388608:case 16777216:case 33554432:e=128;break;case 268435456:e=134217728;break;default:e=0}return e}function I0(e){return e&=-e,2<e?8<e?(e&134217727)!==0?32:268435456:8:2}function BR(){var e=Oe.p;return e!==0?e:(e=window.event,e===void 0?32:TN(e.type))}function HC(e,t){var o=Oe.p;try{return Oe.p=e,t()}finally{Oe.p=o}}var Bn=Math.random().toString(36).slice(2),$t="__reactFiber$"+Bn,Ao="__reactProps$"+Bn,$l="__reactContainer$"+Bn,FC="__reactEvents$"+Bn,c6="__reactListeners$"+Bn,f6="__reactHandles$"+Bn,$C="__reactResources$"+Bn,sc="__reactMarker$"+Bn,Mm="__reactLoad$"+Bn;function ry(e){delete e[$t],delete e[Ao],delete e[c6],delete e[f6]}function Oi(e){var t;if(t=e[$t])return t;for(var o=e.parentNode;o;){if(t=o[$l]||o[$t]){if(o=t.alternate,t.child!==null||o!==null&&o.child!==null)for(e=sR(e);e!==null;){if(o=e[$t])return o;e=sR(e)}return t}e=o,o=e.parentNode}return null}function ql(e){if(e=e[$t]||e[$l]){var t=e.tag;if(t===5||t===6||t===13||t===31||t===26||t===27||t===3)return e}return null}function Eu(e){var t=e.tag;if(t===5||t===26||t===27||t===6)return e.stateNode;throw Error(z(33))}function xl(e){var t=e[$C];return t||(t=e[$C]={hoistableStyles:new Map,hoistableScripts:new Map}),t}function Dt(e){e[sc]=!0}function LR(e){e[Mm]=void 0}var kR=new Set,IR={};function Fi(e,t){_l(e,t),_l(e+"Capt
Line truncated
|
||||
`).replace(Zj,"")}function KO(e,t){return t=ZE(t),ZE(e)===t}function ke(e,t,o,r,n,a){switch(o){case"children":if(typeof r=="string")t==="body"||t==="textarea"&&r===""||Dl(e,r);else if(typeof r=="number"||typeof r=="bigint")t!=="body"&&Dl(e,""+r);else return;break;case"className":qd(e,"class",r);break;case"tabIndex":qd(e,"tabindex",r);break;case"dir":case"role":case"viewBox":case"width":case"height":qd(e,o,r);break;case"style":GR(e,r,a);return;case"data":if(t!=="object"){qd(e,"data",r);break}case"src":case"href":if(r===""&&(t!=="a"||o!=="href")){e.removeAttribute(o);break}if(r==null||typeof r=="function"||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=pm(r),e.setAttribute(o,r);break;case"action":case"formAction":if(typeof r=="function"){e.setAttribute(o,"javascript:throw new Error('A React form was unexpectedly submitted. If you called form.submit() manually, consider using form.requestSubmit() instead. If you\\'re trying to use event.stopPropagation() in a submit event handler, consider also calling event.preventDefault().')");break}else typeof a=="function"&&(o==="formAction"?(t!=="input"&&ke(e,t,"name",n.name,n,null),ke(e,t,"formEncType",n.formEncType,n,null),ke(e,t,"formMethod",n.formMethod,n,null),ke(e,t,"formTarget",n.formTarget,n,null)):(ke(e,t,"encType",n.encType,n,null),ke(e,t,"method",n.method,n,null),ke(e,t,"target",n.target,n,null)));if(r==null||typeof r=="symbol"||typeof r=="boolean"){e.removeAttribute(o);break}r=pm(r),e.setAttribute(o,r);break;case"onClick":r!=null&&(e.onclick=Qr);return;case"onScroll":r!=null&&fe("scroll",e);return;case"onScrollEnd":r!=null&&fe("scrollend",e);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(z(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(z(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"multiple":e.multiple=r&&typeof r!="function"&&typeof r!="symbol";break;case"muted":e.muted=r&&typeof r!="function"&&typeof r!="symbol";break;case"suppressContentEditableWarning":case"suppressHydrationWarning":case"defaultValue":case"defaultChecked":case"innerHTML":case"ref":break;case"autoFocus":break;case"xlinkHref":if(r==null||typeof r=="function"||typeof r=="boolean"||typeof r=="symbol"){e.removeAttribute("xlink:href");break}o=pm(r),e.setAttributeNS("http://www.w3.org/1999/xlink","xlink:href",o);break;case"contentEditable":case"spellCheck":case"draggable":case"value":case"autoReverse":case"externalResourcesRequired":case"focusable":case"preserveAlpha":r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"inert":case"allowFullScreen":case"async":case"autoPlay":case"controls":case"credentialless":case"default":case"defer":case"disabled":case"disablePictureInPicture":case"disableRemotePlayback":case"formNoValidate":case"hidden":case"loop":case"noModule":case"noValidate":case"open":case"playsInline":case"readOnly":case"required":case"reversed":case"scoped":case"seamless":case"itemScope":r&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,""):e.removeAttribute(o);break;case"capture":case"download":r===!0?e.setAttribute(o,""):r!==!1&&r!=null&&typeof r!="function"&&typeof r!="symbol"?e.setAttribute(o,r):e.removeAttribute(o);break;case"cols":case"rows":case"size":case"span":r!=null&&typeof r!="function"&&typeof r!="symbol"&&!isNaN(r)&&1<=r?e.setAttribute(o,r):e.removeAttribute(o);break;case"rowSpan":case"start":r==null||typeof r=="function"||typeof r=="symbol"||isNaN(r)?e.removeAttribute(o):e.setAttribute(o,r);break;case"popover":fe("beforetoggle",e),fe("toggle",e),lm(e,"popover",r);break;case"xlinkActuate":En(e,"http://www.w3.org/1999/xlink","xlink:actuate",r);break;case"xlinkArcrole":En(e,"http://www.w3.org/1999/xlink","xlink:arcrole",r);break;case"xlinkRole":En(e,"http://www.w3.org/1999/xlink","xlink:role",r);break;case"xlinkShow":En(e,"http://www.w3.org/1999/xlink","xlink:show",r);break;case"xlinkTitle":En(e,"http://www.w3.org/1999/xlink","xlink:title",r);break;case"xlinkType":En(e,"http://www.w3.org/1999/xlink","xlink:type",r);break;case"xmlBase":En(e,"http://www.w3.org/XML/1998/namespace","xml:base",r);break;case"xmlLang":En(e,"http://www.w3.org/XML/1998/namespace","xml:lang",r);break;case"xmlSpace":En(e,"http://www.w3.org/XML/1998/namespace","xml:space",r);break;case"is":lm(e,"is",r);break;case"innerText":case"textContent":return;default:if(!(2<o.length)||o[0]!=="o"&&o[0]!=="O"||o[1]!=="n"&&o[1]!=="N")o=T6.get(o)||o,lm(e,o,r);else return}Pe=!0}function E0(e,t,o,r,n,a){switch(o){case"style":GR(e,r,a);return;case"dangerouslySetInnerHTML":if(r!=null){if(typeof r!="object"||!("__html"in r))throw Error(z(61));if(o=r.__html,o!=null){if(n.children!=null)throw Error(z(60));a?.__html!==o&&(e.innerHTML=o)}}break;case"children":if(typeof r=="string")Dl(e,r);else if(typeof r=="number"||typeof r=="bigint")Dl(e,""+r);else return;break;case"onScroll":r!=null&&fe("scroll",e);return;case"onScrollEnd":r!=null&&fe("scrollend",e);return;case"onClick":r
Line truncated
|
||||
${s}.classList.add('${c}'.replace('%s', colorScheme));`}let d=f.match(/\[([^[\]]+)\]/);if(d){let[c,u]=d[1].split("=");u||(p+=`${s}.removeAttribute('${c}'.replace('%s', light));
|
||||
${s}.removeAttribute('${c}'.replace('%s', dark));`),p+=`
|
||||
${s}.setAttribute('${c}'.replace('%s', colorScheme), ${u?`${u}.replace('%s', colorScheme)`:'""'});`}else f!==".%s"&&(p+=`${s}.setAttribute('${f}', colorScheme);`);return(0,Bx.jsx)("script",{suppressHydrationWarning:!0,nonce:typeof window>"u"?l:"",dangerouslySetInnerHTML:{__html:`(function() {
|
||||
${s}.setAttribute('${c}'.replace('%s', colorScheme), ${u?`${u}.replace('%s', colorScheme)`:'""'});`}else f!==".%s"&&(p+=`${s}.setAttribute('${f}', colorScheme);`);return(0,kx.jsx)("script",{suppressHydrationWarning:!0,nonce:typeof window>"u"?l:"",dangerouslySetInnerHTML:{__html:`(function() {
|
||||
try {
|
||||
let colorScheme = '';
|
||||
const mode = localStorage.getItem('${n}') || '${t}';
|
||||
@@ -33,15 +33,15 @@ try {
|
||||
if (colorScheme) {
|
||||
${p}
|
||||
}
|
||||
} catch(e){}})();`}},"mui-color-scheme-init")}var Lt=C(L(),1);function _w(){}var Dw=({key:e,storageWindow:t})=>(!t&&typeof window<"u"&&(t=window),{get(o){if(typeof window>"u")return;if(!t)return o;let r;try{r=t.localStorage.getItem(e)}catch{}return r||o},set:o=>{if(t)try{t.localStorage.setItem(e,o)}catch{}},subscribe:o=>{if(!t)return _w;let r=n=>{let a=n.newValue;n.key===e&&o(a)};return t.addEventListener("storage",r),()=>{t.removeEventListener("storage",r)}}}),Lx=Dw;function ch(){}function kx(e){if(typeof window<"u"&&typeof window.matchMedia=="function"&&e==="system")return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function Ix(e,t){if(e.mode==="light"||e.mode==="system"&&e.systemMode==="light")return t("light");if(e.mode==="dark"||e.mode==="system"&&e.systemMode==="dark")return t("dark")}function zw(e){return Ix(e,t=>{if(t==="light")return e.lightColorScheme;if(t==="dark")return e.darkColorScheme})}function fh(e){let{defaultMode:t="light",defaultLightColorScheme:o,defaultDarkColorScheme:r,supportedColorSchemes:n=[],modeStorageKey:a=fp,colorSchemeStorageKey:i=dp,storageWindow:s=typeof window>"u"?void 0:window,storageManager:l=Lx,noSsr:p=!1}=e,f=n.join(","),d=n.length>1,c=Lt.useMemo(()=>l?.({key:a,storageWindow:s}),[l,a,s]),u=Lt.useMemo(()=>l?.({key:`${i}-light`,storageWindow:s}),[l,i,s]),b=Lt.useMemo(()=>l?.({key:`${i}-dark`,storageWindow:s}),[l,i,s]),[v,x]=Lt.useState(()=>{let R=c?.get(t)||t,N=u?.get(o)||o,O=b?.get(r)||r;return{mode:R,systemMode:kx(R),lightColorScheme:N,darkColorScheme:O}}),[m,h]=Lt.useState(p||!d);Lt.useEffect(()=>{h(!0)},[]);let y=zw(v),g=Lt.useCallback(R=>{x(N=>{if(R===N.mode)return N;let O=R??t;return c?.set(O),{...N,mode:O,systemMode:kx(O)}})},[c,t]),S=Lt.useCallback(R=>{R?typeof R=="string"?R&&!f.includes(R)?console.error(`\`${R}\` does not exist in \`theme.colorSchemes\`.`):x(N=>{let O={...N};return Ix(N,D=>{D==="light"&&(u?.set(R),O.lightColorScheme=R),D==="dark"&&(b?.set(R),O.darkColorScheme=R)}),O}):x(N=>{let O={...N},D=R.light===null?o:R.light,T=R.dark===null?r:R.dark;return D&&(f.includes(D)?(O.lightColorScheme=D,u?.set(D)):console.error(`\`${D}\` does not exist in \`theme.colorSchemes\`.`)),T&&(f.includes(T)?(O.darkColorScheme=T,b?.set(T)):console.error(`\`${T}\` does not exist in \`theme.colorSchemes\`.`)),O}):x(N=>(u?.set(o),b?.set(r),{...N,lightColorScheme:o,darkColorScheme:r}))},[f,u,b,o,r]),P=Lt.useCallback(R=>{v.mode==="system"&&x(N=>{let O=R?.matches?"dark":"light";return N.systemMode===O?N:{...N,systemMode:O}})},[v.mode]),E=Lt.useRef(P);return E.current=P,Lt.useEffect(()=>{if(typeof window.matchMedia!="function"||!d)return;let R=(...O)=>E.current(...O),N=window.matchMedia("(prefers-color-scheme: dark)");return N.addListener(R),R(N),()=>{N.removeListener(R)}},[d]),Lt.useEffect(()=>{if(d){let R=c?.subscribe(D=>{(!D||["light","dark","system"].includes(D))&&g(D||t)})||ch,N=u?.subscribe(D=>{(!D||f.match(D))&&S({light:D})})||ch,O=b?.subscribe(D=>{(!D||f.match(D))&&S({dark:D})})||ch;return()=>{R(),N(),O()}}},[S,g,f,t,s,d,c,u,b]),{...v,mode:m?v.mode:void 0,systemMode:m?v.systemMode:void 0,colorScheme:m?y:void 0,setMode:g,setColorScheme:S}}var vs=C(I(),1),jw="*{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}";function cf(e){let{themeId:t,theme:o={},modeStorageKey:r=fp,colorSchemeStorageKey:n=dp,disableTransitionOnChange:a=!1,defaultColorScheme:i,resolveTheme:s}=e,l={allColorSchemes:[],colorScheme:void 0,darkColorScheme:void 0,lightColorScheme:void 0,mode:void 0,setColorScheme:()=>{},setMode:()=>{},systemMode:void 0},p=kt.createContext(void 0),f=()=>kt.useContext(p)||l,d={},c={};function u(m){let{children:h,theme:y,modeStorageKey:g=r,colorSchemeStorageKey:S=n,disableTransitionOnChange:P=a,storageManager:E,storageWindow:R=typeof window>"u"?void 0:window,documentNode:N=typeof document>"u"?void 0:document,colorSchemeNode:O=typeof document>"u"?void 0:document.documentElement,disableNestedContext:D=!1,disableStyleSheetGeneration:T=!1,defaultMode:A="system",forceThemeRerender:M=!1,noSsr:U}=m,k=kt.useRef(!1),Y=sn(),Z=kt.useContext(p),X=!!Z&&!D,Te=kt.useMemo(()=>y||(typeof o=="function"?o():o),[y]),te=Te[t],ie=te||Te,{colorSchemes:ne=d,components:Je=c,cssVarPrefix:Oe}=ie,ze=Object.keys(ne).filter(nt=>!!ne[nt]).join(","),fe=kt.useMemo(()=>ze.split(","),[ze]),ot=typeof i=="string"?i:i.light,de=typeof i=="string"?i:i.dark,oe=ne[ot]&&ne[de]?A:ne[ie.defaultColorScheme]?.palette?.mode||ie.palette?.mode,{mode:le,setMode:be,systemMode:ee,lightColorScheme:B,darkColorScheme:se,colorScheme:xe,setColorScheme:he}=fh({supportedColorSchemes:fe,defaultLightColorScheme:ot,defaultDarkColorScheme:de,modeStorageKey:g,colorSchemeStorageKey:S,defaultMode:oe,storageManager:E,storageWindow:R,noSsr:U}),Ne=le,et=xe;X&&(Ne=Z.mode,et=Z.colorScheme);let Qt=et||ie.defaultColorScheme;ie.vars&&!M&&(Qt=ie.defaultColorScheme);let rt=kt.useMemo(()=>{let nt=ie.generateThemeVars?.()||ie.varLine truncated
|
||||
} catch(e){}})();`}},"mui-color-scheme-init")}var kt=C(B(),1);function jw(){}var Uw=({key:e,storageWindow:t})=>(!t&&typeof window<"u"&&(t=window),{get(o){if(typeof window>"u")return;if(!t)return o;let r;try{r=t.localStorage.getItem(e)}catch{}return r||o},set:o=>{if(t)try{t.localStorage.setItem(e,o)}catch{}},subscribe:o=>{if(!t)return jw;let r=n=>{let a=n.newValue;n.key===e&&o(a)};return t.addEventListener("storage",r),()=>{t.removeEventListener("storage",r)}}}),Ix=Uw;function dh(){}function Vx(e){if(typeof window<"u"&&typeof window.matchMedia=="function"&&e==="system")return window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light"}function Hx(e,t){if(e.mode==="light"||e.mode==="system"&&e.systemMode==="light")return t("light");if(e.mode==="dark"||e.mode==="system"&&e.systemMode==="dark")return t("dark")}function Bw(e){return Hx(e,t=>{if(t==="light")return e.lightColorScheme;if(t==="dark")return e.darkColorScheme})}function mh(e){let{defaultMode:t="light",defaultLightColorScheme:o,defaultDarkColorScheme:r,supportedColorSchemes:n=[],modeStorageKey:a=gp,colorSchemeStorageKey:i=Tp,storageWindow:s=typeof window>"u"?void 0:window,storageManager:l=Ix,noSsr:p=!1}=e,f=n.join(","),d=n.length>1,c=kt.useMemo(()=>l?.({key:a,storageWindow:s}),[l,a,s]),u=kt.useMemo(()=>l?.({key:`${i}-light`,storageWindow:s}),[l,i,s]),b=kt.useMemo(()=>l?.({key:`${i}-dark`,storageWindow:s}),[l,i,s]),[v,x]=kt.useState(()=>{let R=c?.get(t)||t,N=u?.get(o)||o,O=b?.get(r)||r;return{mode:R,systemMode:Vx(R),lightColorScheme:N,darkColorScheme:O}}),[m,h]=kt.useState(p||!d);kt.useEffect(()=>{h(!0)},[]);let y=Bw(v),g=kt.useCallback(R=>{x(N=>{if(R===N.mode)return N;let O=R??t;return c?.set(O),{...N,mode:O,systemMode:Vx(O)}})},[c,t]),S=kt.useCallback(R=>{R?typeof R=="string"?R&&!f.includes(R)?console.error(`\`${R}\` does not exist in \`theme.colorSchemes\`.`):x(N=>{let O={...N};return Hx(N,D=>{D==="light"&&(u?.set(R),O.lightColorScheme=R),D==="dark"&&(b?.set(R),O.darkColorScheme=R)}),O}):x(N=>{let O={...N},D=R.light===null?o:R.light,T=R.dark===null?r:R.dark;return D&&(f.includes(D)?(O.lightColorScheme=D,u?.set(D)):console.error(`\`${D}\` does not exist in \`theme.colorSchemes\`.`)),T&&(f.includes(T)?(O.darkColorScheme=T,b?.set(T)):console.error(`\`${T}\` does not exist in \`theme.colorSchemes\`.`)),O}):x(N=>(u?.set(o),b?.set(r),{...N,lightColorScheme:o,darkColorScheme:r}))},[f,u,b,o,r]),P=kt.useCallback(R=>{v.mode==="system"&&x(N=>{let O=R?.matches?"dark":"light";return N.systemMode===O?N:{...N,systemMode:O}})},[v.mode]),E=kt.useRef(P);return E.current=P,kt.useEffect(()=>{if(typeof window.matchMedia!="function"||!d)return;let R=(...O)=>E.current(...O),N=window.matchMedia("(prefers-color-scheme: dark)");return N.addListener(R),R(N),()=>{N.removeListener(R)}},[d]),kt.useEffect(()=>{if(d){let R=c?.subscribe(D=>{(!D||["light","dark","system"].includes(D))&&g(D||t)})||dh,N=u?.subscribe(D=>{(!D||f.match(D))&&S({light:D})})||dh,O=b?.subscribe(D=>{(!D||f.match(D))&&S({dark:D})})||dh;return()=>{R(),N(),O()}}},[S,g,f,t,s,d,c,u,b]),{...v,mode:m?v.mode:void 0,systemMode:m?v.systemMode:void 0,colorScheme:m?y:void 0,setMode:g,setColorScheme:S}}var Ps=C(k(),1),Lw="*{-webkit-transition:none!important;-moz-transition:none!important;-o-transition:none!important;-ms-transition:none!important;transition:none!important}";function yf(e){let{themeId:t,theme:o={},modeStorageKey:r=gp,colorSchemeStorageKey:n=Tp,disableTransitionOnChange:a=!1,defaultColorScheme:i,resolveTheme:s}=e,l={allColorSchemes:[],colorScheme:void 0,darkColorScheme:void 0,lightColorScheme:void 0,mode:void 0,setColorScheme:()=>{},setMode:()=>{},systemMode:void 0},p=It.createContext(void 0),f=()=>It.useContext(p)||l,d={},c={};function u(m){let{children:h,theme:y,modeStorageKey:g=r,colorSchemeStorageKey:S=n,disableTransitionOnChange:P=a,storageManager:E,storageWindow:R=typeof window>"u"?void 0:window,documentNode:N=typeof document>"u"?void 0:document,colorSchemeNode:O=typeof document>"u"?void 0:document.documentElement,disableNestedContext:D=!1,disableStyleSheetGeneration:T=!1,defaultMode:A="system",forceThemeRerender:M=!1,noSsr:U}=m,L=It.useRef(!1),G=un(),J=It.useContext(p),K=!!J&&!D,he=It.useMemo(()=>y||(typeof o=="function"?o():o),[y]),re=he[t],se=re||he,{colorSchemes:ie=d,components:Xe=c,cssVarPrefix:Ne}=se,Ce=Object.keys(ie).filter(nt=>!!ie[nt]).join(","),me=It.useMemo(()=>Ce.split(","),[Ce]),ot=typeof i=="string"?i:i.light,ge=typeof i=="string"?i:i.dark,oe=ie[ot]&&ie[ge]?A:ie[se.defaultColorScheme]?.palette?.mode||se.palette?.mode,{mode:X,setMode:Q,systemMode:Ee,lightColorScheme:Y,darkColorScheme:ce,colorScheme:we,setColorScheme:Te}=mh({supportedColorSchemes:me,defaultLightColorScheme:ot,defaultDarkColorScheme:ge,modeStorageKey:g,colorSchemeStorageKey:S,defaultMode:oe,storageManager:E,storageWindow:R,noSsr:U}),Ae=X,et=we;K&&(Ae=J.mode,et=J.colorScheme);let Qt=et||se.defaultColorScheme;se.vars&&!M&&(Qt=se.defaultColorScheme);let rt=It.useMemo(()=>{let nt=se.generateThemeVars?.()||se.vars,HLine truncated
|
||||
|
||||
const theme = ${JSON.stringify(t,null,2)};
|
||||
|
||||
theme.breakpoints = createBreakpoints(theme.breakpoints || {});
|
||||
theme.transitions = createTransitions(theme.transitions || {});
|
||||
|
||||
export default theme;`}function t1(e){return typeof e=="number"?`${(e*100).toFixed(0)}%`:`calc((${e}) * 100%)`}var lA=e=>{if(!Number.isNaN(+e))return+e;let t=e.match(/\d*\.?\d+/g);if(!t)return 0;let o=0;for(let r=0;r<t.length;r+=1)o+=+t[r];return o};function pA(e){Object.assign(e,{alpha(t,o){let r=this||e;return r.colorSpace?`oklch(from ${t} l c h / ${typeof o=="string"?`calc(${o})`:o})`:r.vars?`rgba(${t.replace(/var\(--([^,\s)]+)(?:,[^)]+)?\)+/g,"var(--$1Channel)")} / ${typeof o=="string"?`calc(${o})`:o})`:$n(t,lA(o))},lighten(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #fff ${t1(o)})`:gs(t,o)},darken(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #000 ${t1(o)})`:hs(t,o)}})}function uA(e={},...t){let{breakpoints:o,mixins:r={},spacing:n,palette:a={},transitions:i={},typography:s={},shape:l,colorSpace:p,...f}=e;if(e.vars&&e.generateThemeVars===void 0)throw new Error(Ot(20));let d=Za({...a,colorSpace:p}),c=vr(e),u=Pe(c,{mixins:hh(c.breakpoints,r),palette:d,shadows:Wx.slice(),typography:yp(d,s),transitions:Th(i),zIndex:{...e1}});return u=Pe(u,f),u=t.reduce((b,v)=>Pe(b,v),u),u.unstable_sxConfig={...br,...f?.unstable_sxConfig},u.unstable_sx=function(v){return To({sx:v,theme:this})},u.toRuntimeSource=Tf,pA(u),u}var hp=uA;function Ss(e){let t;return e<1?t=5.11916*e**2:t=4.5*Math.log(e+1)+2,Math.round(t*10)/1e3}var cA=[...Array(25)].map((e,t)=>{if(t===0)return"none";let o=Ss(t);return`linear-gradient(rgba(255 255 255 / ${o}), rgba(255 255 255 / ${o}))`});function bh(e){return{inputPlaceholder:e==="dark"?.5:.42,inputUnderline:e==="dark"?.7:.42,switchTrackDisabled:e==="dark"?.2:.12,switchTrack:e==="dark"?.3:.38}}function vh(e){return e==="dark"?cA:[]}function xh(e){let{palette:t={mode:"light"},opacity:o,overlays:r,colorSpace:n,...a}=e,i=Za({...t,colorSpace:n});return{palette:i,opacity:{...bh(i.mode),...o},overlays:r||vh(i.mode),...a}}function Sh(e){return!!e[0].match(/(cssVarPrefix|colorSchemeSelector|modularCssLayers|rootSelector|typography|mixins|breakpoints|direction|transitions)/)||!!e[0].match(/sxConfig$/)||e[0]==="palette"&&!!e[1]?.match(/(mode|contrastThreshold|tonalOffset)/)}var fA=e=>[...[...Array(25)].map((t,o)=>`--${e?`${e}-`:""}overlays-${o}`),`--${e?`${e}-`:""}palette-AppBar-darkBg`,`--${e?`${e}-`:""}palette-AppBar-darkColor`],o1=fA;var r1=e=>(t,o)=>{let r=e.rootSelector||":root",n=e.colorSchemeSelector,a=n;if(n==="class"&&(a=".%s"),n==="data"&&(a="[data-%s]"),n?.startsWith("data-")&&!n.includes("%s")&&(a=`[${n}="%s"]`),e.defaultColorScheme===t){if(t==="dark"){let i={};return o1(e.cssVarPrefix).forEach(s=>{i[s]=o[s],delete o[s]}),a==="media"?{[r]:o,"@media (prefers-color-scheme: dark)":{[r]:i}}:a?{[a.replace("%s",t)]:i,[`${r}, ${a.replace("%s",t)}`]:o}:{[r]:{...o,...i}}}if(a&&a!=="media")return`${r}, ${a.replace("%s",String(t))}`}else if(t){if(a==="media")return{[`@media (prefers-color-scheme: ${String(t)})`]:{[r]:o}};if(a)return a.replace("%s",String(t))}return r};function dA(e,t){t.forEach(o=>{e[o]||(e[o]={})})}function _(e,t,o){!e[t]&&o&&(e[t]=o)}function gp(e){return typeof e!="string"||!e.startsWith("hsl")?e:ih(e)}function ln(e,t){`${t}Channel`in e||(e[`${t}Channel`]=ys(gp(e[t]),`MUI: Can't create \`palette.${t}Channel\` because \`palette.${t}\` is not one of these formats: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla(), color().
|
||||
To suppress this warning, you need to explicitly provide the \`palette.${t}Channel\` as a string (in rgb format, for example "12 12 12") or undefined if you want to remove the channel token.`))}function mA(e){return typeof e=="number"?`${e}px`:typeof e=="string"||typeof e=="function"||Array.isArray(e)?e:"8px"}var jr=e=>{try{return e()}catch{}},yA=(e="mui")=>ff(e);function Ph(e,t,o,r,n){if(!o)return;o=o===!0?{}:o;let a=n==="dark"?"dark":"light";if(!r){t[n]=xh({...o,palette:{mode:a,...o?.palette},colorSpace:e});return}let{palette:i,...s}=hp({...r,palette:{mode:a,...o?.palette},colorSpace:e});return t[n]={...o,palette:i,opacity:{...bh(a),...o?.opacity},overlays:o?.overlays||vh(a)},s}function Ch(e={},...t){let{colorSchemes:o={light:!0},defaultColorScheme:r,disableCssColorScheme:n=!1,cssVarPrefix:a="mui",nativeColor:i=!1,shouldSkipGeneratingVar:s=Sh,colorSchemeSelector:l=o.light&&o.dark?"media":void 0,rootSelector:p=":root",...f}=e,d=Object.keys(o)[0],c=r||(o.light&&d!=="light"?"light":d),u=yA(a),{[c]:b,light:v,dark:x,...m}=o,h={...m},y=b;if((c==="dark"&&!("dark"in o)||c==="light"&&!("light"in o))&&(y=!0),!y)throw new Error(Ot(21,c));let g;i&&(g="oklch");let S=Ph(g,h,y,f,c);v&&!h.light&&Ph(g,h,v,void 0,"light"),x&&!h.dark&&Ph(g,h,x,void 0,"dark");let P={defaultColorScheme:c,...S,cssVarPrefix:a,colorSchemeSelector:l,rootSelector:p,getCssVar:u,colorSchemes:h,font:{...gf(S.typography),...S.font},spacing:mA(f.spacing)};Object.keys(P.colorSchemes).forEach(D=>{let T=P.colorSchemes[D].palette,A=U=>{let k=U.split("-"),Y=k[1],Z=k[2];return u(U,T[Y][Z])};T.mode==="light"&&(_(T.common,"background","#fff"),_(T.common,"onBackground","#000")),T.mode==="dark"&&(_(T.common,"background","#000"),_(T.common,"onBackground","#fff"));function M(U,k,Y){if(g){let Z;return U===qn&&(Z=`transparent ${((1-Y)*100).toFixed(0)}%`),U===Ae&&(Z=`#000 ${(Y*100).toFixed(0)}%`),U===Me&&(Z=`#fff ${(Y*100).toFixed(0)}%`),`color-mix(in ${g}, ${k}, ${Z})`}return U(k,Y)}if(dA(T,["Alert","AppBar","Avatar","Button","Chip","FilledInput","LinearProgress","Skeleton","Slider","SnackbarContent","SpeedDialAction","StepConnector","StepContent","Switch","TableCell","Tooltip"]),T.mode==="light"){_(T.Alert,"errorColor",M(Ae,i?u("palette-error-light"):T.error.light,.6)),_(T.Alert,"infoColor",M(Ae,i?u("palette-info-light"):T.info.light,.6)),_(T.Alert,"successColor",M(Ae,i?u("palette-success-light"):T.success.light,.6)),_(T.Alert,"warningColor",M(Ae,i?u("palette-warning-light"):T.warning.light,.6)),_(T.Alert,"errorFilledBg",A("palette-error-main")),_(T.Alert,"infoFilledBg",A("palette-info-main")),_(T.Alert,"successFilledBg",A("palette-success-main")),_(T.Alert,"warningFilledBg",A("palette-warning-main")),_(T.Alert,"errorFilledColor",jr(()=>T.getContrastText(T.error.main))),_(T.Alert,"infoFilledColor",jr(()=>T.getContrastText(T.info.main))),_(T.Alert,"successFilledColor",jr(()=>T.getContrastText(T.success.main))),_(T.Alert,"warningFilledColor",jr(()=>T.getContrastText(T.warning.main))),_(T.Alert,"errorStandardBg",M(Me,i?u("palette-error-light"):T.error.light,.9)),_(T.Alert,"infoStandardBg",M(Me,i?u("palette-info-light"):T.info.light,.9)),_(T.Alert,"successStandardBg",M(Me,i?u("palette-success-light"):T.success.light,.9)),_(T.Alert,"warningStandardBg",M(Me,i?u("palette-warning-light"):T.warning.light,.9)),_(T.Alert,"errorIconColor",A("palette-error-main")),_(T.Alert,"infoIconColor",A("palette-info-main")),_(T.Alert,"successIconColor",A("palette-success-main")),_(T.Alert,"warningIconColor",A("palette-warning-main")),_(T.AppBar,"defaultBg",A("palette-grey-100")),_(T.Avatar,"defaultBg",A("palette-grey-400")),_(T.Button,"inheritContainedBg",A("palette-grey-300")),_(T.Button,"inheritContainedHoverBg",A("palette-grey-A100")),_(T.Chip,"defaultBorder",A("palette-grey-400")),_(T.Chip,"defaultAvatarColor",A("palette-grey-700")),_(T.Chip,"defaultIconColor",A("palette-grey-700")),_(T.FilledInput,"bg","rgba(0, 0, 0, 0.06)"),_(T.FilledInput,"hoverBg","rgba(0, 0, 0, 0.09)"),_(T.FilledInput,"disabledBg","rgba(0, 0, 0, 0.12)"),_(T.LinearProgress,"primaryBg",M(Me,i?u("palette-primary-main"):T.primary.main,.62)),_(T.LinearProgress,"secondaryBg",M(Me,i?u("palette-secondary-main"):T.secondary.main,.62)),_(T.LinearProgress,"errorBg",M(Me,i?u("palette-error-main"):T.error.main,.62)),_(T.LinearProgress,"infoBg",M(Me,i?u("palette-info-main"):T.info.main,.62)),_(T.LinearProgress,"successBg",M(Me,i?u("palette-success-main"):T.success.main,.62)),_(T.LinearProgress,"warningBg",M(Me,i?u("palette-warning-light"):T.warning.main,.62)),_(T.Skeleton,"bg",g?M(qn,i?u("palette-text-primary"):T.text.primary,.11):`rgba(${A("palette-text-primaryChannel")} / 0.11)`),_(T.Slider,"primaryTrack",M(Me,i?u("palette-primary-main"):T.primary.main,.62)),_(T.Slider,"secondaryTrack",M(Me,i?u("palette-secondary-main"):T.secondary.main,.62)),_(T.Slider,"errorTrack",M(Me,i?u("palette-error-main"):T.error.main,.62)),_(T.Slider,"infoTrack",M(Me,i?u("palette-info-main"):T.info.main,.62)),_(T.Slider,"successTrack",M(Me,i?u("palLine truncated
|
||||
export default theme;`}function r1(e){return typeof e=="number"?`${(e*100).toFixed(0)}%`:`calc((${e}) * 100%)`}var cA=e=>{if(!Number.isNaN(+e))return+e;let t=e.match(/\d*\.?\d+/g);if(!t)return 0;let o=0;for(let r=0;r<t.length;r+=1)o+=+t[r];return o};function fA(e){Object.assign(e,{alpha(t,o){let r=this||e;return r.colorSpace?`oklch(from ${t} l c h / ${typeof o=="string"?`calc(${o})`:o})`:r.vars?`rgba(${t.replace(/var\(--([^,\s)]+)(?:,[^)]+)?\)+/g,"var(--$1Channel)")} / ${typeof o=="string"?`calc(${o})`:o})`:Yn(t,cA(o))},lighten(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #fff ${r1(o)})`:vs(t,o)},darken(t,o){let r=this||e;return r.colorSpace?`color-mix(in ${r.colorSpace}, ${t}, #000 ${r1(o)})`:bs(t,o)}})}function dA(e={},...t){let{breakpoints:o,mixins:r={},spacing:n,palette:a={},transitions:i={},typography:s={},shape:l,colorSpace:p,...f}=e;if(e.vars&&e.generateThemeVars===void 0)throw new Error(Nt(20));let d=ei({...a,colorSpace:p}),c=Sr(e),u=Se(c,{mixins:Th(c.breakpoints,r),palette:d,shadows:e1.slice(),typography:vp(d,s),transitions:vh(i),zIndex:{...o1}});return u=Se(u,f),u=t.reduce((b,v)=>Se(b,v),u),u.unstable_sxConfig={...xr,...f?.unstable_sxConfig},u.unstable_sx=function(v){return vo({sx:v,theme:this})},u.toRuntimeSource=Sf,fA(u),u}var xp=dA;function Es(e){let t;return e<1?t=5.11916*e**2:t=4.5*Math.log(e+1)+2,Math.round(t*10)/1e3}var mA=[...Array(25)].map((e,t)=>{if(t===0)return"none";let o=Es(t);return`linear-gradient(rgba(255 255 255 / ${o}), rgba(255 255 255 / ${o}))`});function xh(e){return{inputPlaceholder:e==="dark"?.5:.42,inputUnderline:e==="dark"?.7:.42,switchTrackDisabled:e==="dark"?.2:.12,switchTrack:e==="dark"?.3:.38}}function Sh(e){return e==="dark"?mA:[]}function Ph(e){let{palette:t={mode:"light"},opacity:o,overlays:r,colorSpace:n,...a}=e,i=ei({...t,colorSpace:n});return{palette:i,opacity:{...xh(i.mode),...o},overlays:r||Sh(i.mode),...a}}function Ch(e){return!!e[0].match(/(cssVarPrefix|colorSchemeSelector|modularCssLayers|rootSelector|typography|mixins|breakpoints|direction|transitions)/)||!!e[0].match(/sxConfig$/)||e[0]==="palette"&&!!e[1]?.match(/(mode|contrastThreshold|tonalOffset)/)}var yA=e=>[...[...Array(25)].map((t,o)=>`--${e?`${e}-`:""}overlays-${o}`),`--${e?`${e}-`:""}palette-AppBar-darkBg`,`--${e?`${e}-`:""}palette-AppBar-darkColor`],n1=yA;var a1=e=>(t,o)=>{let r=e.rootSelector||":root",n=e.colorSchemeSelector,a=n;if(n==="class"&&(a=".%s"),n==="data"&&(a="[data-%s]"),n?.startsWith("data-")&&!n.includes("%s")&&(a=`[${n}="%s"]`),e.defaultColorScheme===t){if(t==="dark"){let i={};return n1(e.cssVarPrefix).forEach(s=>{i[s]=o[s],delete o[s]}),a==="media"?{[r]:o,"@media (prefers-color-scheme: dark)":{[r]:i}}:a?{[a.replace("%s",t)]:i,[`${r}, ${a.replace("%s",t)}`]:o}:{[r]:{...o,...i}}}if(a&&a!=="media")return`${r}, ${a.replace("%s",String(t))}`}else if(t){if(a==="media")return{[`@media (prefers-color-scheme: ${String(t)})`]:{[r]:o}};if(a)return a.replace("%s",String(t))}return r};function hA(e,t){t.forEach(o=>{e[o]||(e[o]={})})}function _(e,t,o){!e[t]&&o&&(e[t]=o)}function Sp(e){return typeof e!="string"||!e.startsWith("hsl")?e:lh(e)}function cn(e,t){`${t}Channel`in e||(e[`${t}Channel`]=Ts(Sp(e[t]),`MUI: Can't create \`palette.${t}Channel\` because \`palette.${t}\` is not one of these formats: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla(), color().
|
||||
To suppress this warning, you need to explicitly provide the \`palette.${t}Channel\` as a string (in rgb format, for example "12 12 12") or undefined if you want to remove the channel token.`))}function gA(e){return typeof e=="number"?`${e}px`:typeof e=="string"||typeof e=="function"||Array.isArray(e)?e:"8px"}var Br=e=>{try{return e()}catch{}},TA=(e="mui")=>hf(e);function Eh(e,t,o,r,n){if(!o)return;o=o===!0?{}:o;let a=n==="dark"?"dark":"light";if(!r){t[n]=Ph({...o,palette:{mode:a,...o?.palette},colorSpace:e});return}let{palette:i,...s}=xp({...r,palette:{mode:a,...o?.palette},colorSpace:e});return t[n]={...o,palette:i,opacity:{...xh(a),...o?.opacity},overlays:o?.overlays||Sh(a)},s}function Rh(e={},...t){let{colorSchemes:o={light:!0},defaultColorScheme:r,disableCssColorScheme:n=!1,cssVarPrefix:a="mui",nativeColor:i=!1,shouldSkipGeneratingVar:s=Ch,colorSchemeSelector:l=o.light&&o.dark?"media":void 0,rootSelector:p=":root",...f}=e,d=Object.keys(o)[0],c=r||(o.light&&d!=="light"?"light":d),u=TA(a),{[c]:b,light:v,dark:x,...m}=o,h={...m},y=b;if((c==="dark"&&!("dark"in o)||c==="light"&&!("light"in o))&&(y=!0),!y)throw new Error(Nt(21,c));let g;i&&(g="oklch");let S=Eh(g,h,y,f,c);v&&!h.light&&Eh(g,h,v,void 0,"light"),x&&!h.dark&&Eh(g,h,x,void 0,"dark");let P={defaultColorScheme:c,...S,cssVarPrefix:a,colorSchemeSelector:l,rootSelector:p,getCssVar:u,colorSchemes:h,font:{...xf(S.typography),...S.font},spacing:gA(f.spacing)};Object.keys(P.colorSchemes).forEach(D=>{let T=P.colorSchemes[D].palette,A=U=>{let L=U.split("-"),G=L[1],J=L[2];return u(U,T[G][J])};T.mode==="light"&&(_(T.common,"background","#fff"),_(T.common,"onBackground","#000")),T.mode==="dark"&&(_(T.common,"background","#000"),_(T.common,"onBackground","#fff"));function M(U,L,G){if(g){let J;return U===Xn&&(J=`transparent ${((1-G)*100).toFixed(0)}%`),U===_e&&(J=`#000 ${(G*100).toFixed(0)}%`),U===De&&(J=`#fff ${(G*100).toFixed(0)}%`),`color-mix(in ${g}, ${L}, ${J})`}return U(L,G)}if(hA(T,["Alert","AppBar","Avatar","Button","Chip","FilledInput","LinearProgress","Skeleton","Slider","SnackbarContent","SpeedDialAction","StepConnector","StepContent","Switch","TableCell","Tooltip"]),T.mode==="light"){_(T.Alert,"errorColor",M(_e,i?u("palette-error-light"):T.error.light,.6)),_(T.Alert,"infoColor",M(_e,i?u("palette-info-light"):T.info.light,.6)),_(T.Alert,"successColor",M(_e,i?u("palette-success-light"):T.success.light,.6)),_(T.Alert,"warningColor",M(_e,i?u("palette-warning-light"):T.warning.light,.6)),_(T.Alert,"errorFilledBg",A("palette-error-main")),_(T.Alert,"infoFilledBg",A("palette-info-main")),_(T.Alert,"successFilledBg",A("palette-success-main")),_(T.Alert,"warningFilledBg",A("palette-warning-main")),_(T.Alert,"errorFilledColor",Br(()=>T.getContrastText(T.error.main))),_(T.Alert,"infoFilledColor",Br(()=>T.getContrastText(T.info.main))),_(T.Alert,"successFilledColor",Br(()=>T.getContrastText(T.success.main))),_(T.Alert,"warningFilledColor",Br(()=>T.getContrastText(T.warning.main))),_(T.Alert,"errorStandardBg",M(De,i?u("palette-error-light"):T.error.light,.9)),_(T.Alert,"infoStandardBg",M(De,i?u("palette-info-light"):T.info.light,.9)),_(T.Alert,"successStandardBg",M(De,i?u("palette-success-light"):T.success.light,.9)),_(T.Alert,"warningStandardBg",M(De,i?u("palette-warning-light"):T.warning.light,.9)),_(T.Alert,"errorIconColor",A("palette-error-main")),_(T.Alert,"infoIconColor",A("palette-info-main")),_(T.Alert,"successIconColor",A("palette-success-main")),_(T.Alert,"warningIconColor",A("palette-warning-main")),_(T.AppBar,"defaultBg",A("palette-grey-100")),_(T.Avatar,"defaultBg",A("palette-grey-400")),_(T.Button,"inheritContainedBg",A("palette-grey-300")),_(T.Button,"inheritContainedHoverBg",A("palette-grey-A100")),_(T.Chip,"defaultBorder",A("palette-grey-400")),_(T.Chip,"defaultAvatarColor",A("palette-grey-700")),_(T.Chip,"defaultIconColor",A("palette-grey-700")),_(T.FilledInput,"bg","rgba(0, 0, 0, 0.06)"),_(T.FilledInput,"hoverBg","rgba(0, 0, 0, 0.09)"),_(T.FilledInput,"disabledBg","rgba(0, 0, 0, 0.12)"),_(T.LinearProgress,"primaryBg",M(De,i?u("palette-primary-main"):T.primary.main,.62)),_(T.LinearProgress,"secondaryBg",M(De,i?u("palette-secondary-main"):T.secondary.main,.62)),_(T.LinearProgress,"errorBg",M(De,i?u("palette-error-main"):T.error.main,.62)),_(T.LinearProgress,"infoBg",M(De,i?u("palette-info-main"):T.info.main,.62)),_(T.LinearProgress,"successBg",M(De,i?u("palette-success-main"):T.success.main,.62)),_(T.LinearProgress,"warningBg",M(De,i?u("palette-warning-light"):T.warning.main,.62)),_(T.Skeleton,"bg",g?M(Xn,i?u("palette-text-primary"):T.text.primary,.11):`rgba(${A("palette-text-primaryChannel")} / 0.11)`),_(T.Slider,"primaryTrack",M(De,i?u("palette-primary-main"):T.primary.main,.62)),_(T.Slider,"secondaryTrack",M(De,i?u("palette-secondary-main"):T.secondary.main,.62)),_(T.Slider,"errorTrack",M(De,i?u("palette-error-main"):T.error.main,.62)),_(T.Slider,"infoTrack",M(De,i?u("palette-info-main"):T.info.main,.62)),_(T.Slider,"successTrack",M(De,i?u("palLine truncated
|
||||
0% {
|
||||
transform: scale(0);
|
||||
opacity: 0.1;
|
||||
@@ -51,7 +51,7 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
transform: scale(1);
|
||||
opacity: 0.3;
|
||||
}
|
||||
`,dM=ho`
|
||||
`,hM=To`
|
||||
0% {
|
||||
opacity: 1;
|
||||
}
|
||||
@@ -59,7 +59,7 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
100% {
|
||||
opacity: 0;
|
||||
}
|
||||
`,mM=ho`
|
||||
`,gM=To`
|
||||
0% {
|
||||
transform: scale(1);
|
||||
}
|
||||
@@ -71,23 +71,23 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
100% {
|
||||
transform: scale(1);
|
||||
}
|
||||
`,yM=w("span",{name:"MuiTouchRipple",slot:"Root"})({overflow:"hidden",pointerEvents:"none",position:"absolute",zIndex:0,top:0,right:0,bottom:0,left:0,borderRadius:"inherit"}),hM=w(L1,{name:"MuiTouchRipple",slot:"Ripple"})`
|
||||
`,TM=w("span",{name:"MuiTouchRipple",slot:"Root"})({overflow:"hidden",pointerEvents:"none",position:"absolute",zIndex:0,top:0,right:0,bottom:0,left:0,borderRadius:"inherit"}),bM=w(I1,{name:"MuiTouchRipple",slot:"Ripple"})`
|
||||
opacity: 0;
|
||||
position: absolute;
|
||||
|
||||
&.${Do.rippleVisible} {
|
||||
&.${jo.rippleVisible} {
|
||||
opacity: 0.3;
|
||||
transform: scale(1);
|
||||
animation-name: ${fM};
|
||||
animation-duration: ${kh}ms;
|
||||
animation-name: ${yM};
|
||||
animation-duration: ${Vh}ms;
|
||||
animation-timing-function: ${({theme:e})=>e.transitions.easing.easeInOut};
|
||||
}
|
||||
|
||||
&.${Do.ripplePulsate} {
|
||||
&.${jo.ripplePulsate} {
|
||||
animation-duration: ${({theme:e})=>e.transitions.duration.shorter}ms;
|
||||
}
|
||||
|
||||
& .${Do.child} {
|
||||
& .${jo.child} {
|
||||
opacity: 1;
|
||||
display: block;
|
||||
width: 100%;
|
||||
@@ -96,25 +96,25 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
background-color: currentColor;
|
||||
}
|
||||
|
||||
& .${Do.childLeaving} {
|
||||
& .${jo.childLeaving} {
|
||||
opacity: 0;
|
||||
animation-name: ${dM};
|
||||
animation-duration: ${kh}ms;
|
||||
animation-name: ${hM};
|
||||
animation-duration: ${Vh}ms;
|
||||
animation-timing-function: ${({theme:e})=>e.transitions.easing.easeInOut};
|
||||
}
|
||||
|
||||
& .${Do.childPulsate} {
|
||||
& .${jo.childPulsate} {
|
||||
position: absolute;
|
||||
/* @noflip */
|
||||
left: 0px;
|
||||
top: 0;
|
||||
animation-name: ${mM};
|
||||
animation-name: ${gM};
|
||||
animation-duration: 2500ms;
|
||||
animation-timing-function: ${({theme:e})=>e.transitions.easing.easeInOut};
|
||||
animation-iteration-count: infinite;
|
||||
animation-delay: 200ms;
|
||||
}
|
||||
`,gM=Pt.forwardRef(function(t,o){let r=F({props:t,name:"MuiTouchRipple"}),{center:n=!1,classes:a={},className:i,...s}=r,[l,p]=Pt.useState([]),f=Pt.useRef(0),d=Pt.useRef(null);Pt.useEffect(()=>{d.current&&(d.current(),d.current=null)},[l]);let c=Pt.useRef(!1),u=Xn(),b=Pt.useRef(null),v=Pt.useRef(null),x=Pt.useCallback(g=>{let{pulsate:S,rippleX:P,rippleY:E,rippleSize:R,cb:N}=g;p(O=>[...O,(0,Hf.jsx)(hM,{classes:{ripple:j(a.ripple,Do.ripple),rippleVisible:j(a.rippleVisible,Do.rippleVisible),ripplePulsate:j(a.ripplePulsate,Do.ripplePulsate),child:j(a.child,Do.child),childLeaving:j(a.childLeaving,Do.childLeaving),childPulsate:j(a.childPulsate,Do.childPulsate)},timeout:kh,pulsate:S,rippleX:P,rippleY:E,rippleSize:R},f.current)]),f.current+=1,d.current=N},[a]),m=Pt.useCallback((g={},S={},P=()=>{})=>{let{pulsate:E=!1,center:R=n||S.pulsate,fakeElement:N=!1}=S;if(g?.type==="mousedown"&&c.current){c.current=!1;return}g?.type==="touchstart"&&(c.current=!0);let O=N?null:v.current,D=O?O.getBoundingClientRect():{width:0,height:0,left:0,top:0},T,A,M;if(R||g===void 0||g.clientX===0&&g.clientY===0||!g.clientX&&!g.touches)T=Math.round(D.width/2),A=Math.round(D.height/2);else{let{clientX:U,clientY:k}=g.touches&&g.touches.length>0?g.touches[0]:g;T=Math.round(U-D.left),A=Math.round(k-D.top)}if(R)M=Math.sqrt((2*D.width**2+D.height**2)/3),M%2===0&&(M+=1);else{let U=Math.max(Math.abs((O?O.clientWidth:0)-T),T)*2+2,k=Math.max(Math.abs((O?O.clientHeight:0)-A),A)*2+2;M=Math.sqrt(U**2+k**2)}g?.touches?b.current===null&&(b.current=()=>{x({pulsate:E,rippleX:T,rippleY:A,rippleSize:M,cb:P})},u.start(cM,()=>{b.current&&(b.current(),b.current=null)})):x({pulsate:E,rippleX:T,rippleY:A,rippleSize:M,cb:P})},[n,x,u]),h=Pt.useCallback(()=>{m({},{pulsate:!0})},[m]),y=Pt.useCallback((g,S)=>{if(u.clear(),g?.type==="touchend"&&b.current){b.current(),b.current=null,u.start(0,()=>{y(g,S)});return}b.current=null,p(P=>P.length>0?P.slice(1):P),d.current=S},[u]);return Pt.useImperativeHandle(o,()=>({pulsate:h,start:m,stop:y}),[h,m,y]),(0,Hf.jsx)(yM,{className:j(Do.root,a.root,i),ref:v,...s,children:(0,Hf.jsx)(_h,{component:null,exit:!0,children:l})})}),k1=gM;function I1(e){return V("MuiButtonBase",e)}var TM=$("MuiButtonBase",["root","disabled","focusVisible"]),V1=TM;var Ff=C(I(),1),bM=e=>{let{disabled:t,focusVisible:o,focusVisibleClassName:r,classes:n}=e,i=H({root:["root",t&&"disabled",o&&"focusVisible"]},I1,n);return o&&r&&(i.root+=` ${r}`),i},vM=w("button",{name:"MuiButtonBase",slot:"Root"})({display:"inline-flex",alignItems:"center",justifyContent:"center",position:"relative",boxSizing:"border-box",WebkitTapHighlightColor:"transparent",backgroundColor:"transparent",outline:0,border:0,margin:0,borderRadius:0,padding:0,cursor:"pointer",userSelect:"none",verticalAlign:"middle",MozAppearance:"none",WebkitAppearance:"none",textDecoration:"none",color:"inherit","&::-moz-focus-inner":{borderStyle:"none"},[`&.${V1.disabled}`]:{pointerEvents:"none",cursor:"default"},"@media print":{colorAdjust:"exact"}}),xM=Br.forwardRef(function(t,o){let r=F({props:t,name:"MuiButtonBase"}),{action:n,centerRipple:a=!1,children:i,className:s,component:l="button",disabled:p=!1,disableRipple:f=!1,disableTouchRipple:d=!1,focusRipple:c=!1,focusVisibleClassName:u,LinkComponent:b="a",onBlur:v,onClick:x,onContextMenu:m,onDragLeave:h,onFocus:y,onFocusVisible:g,onKeyDown:S,onKeyUp:P,onMouseDown:E,onMouseLeave:R,onMouseUp:N,onTouchEnd:O,onTouchMove:D,onTouchStart:T,tabIndex:A=0,TouchRippleProps:M,touchRippleRef:U,type:k,...Y}=r,Z=Br.useRef(null),X=If(),Te=Tt(X.ref,U),[te,ie]=Br.useState(!1);p&&te&&ie(!1),Br.useImperativeHandle(n,()=>({focusVisible:()=>{ie(!0),Z.current.focus()}}),[]);let ne=X.shouldMount&&!f&&!p;Br.useEffect(()=>{te&&c&&!f&&X.pulsate()},[f,c,te,X]);let Je=dn(X,"start",E,d),Oe=dn(X,"stop",m,d),ze=dn(X,"stop",h,d),fe=dn(X,"stop",N,d),ot=dn(X,"stop",W=>{te&&W.preventDefault(),R&&R(W)},d),de=dn(X,"start",T,d),oe=dn(X,"stop",O,d),le=dn(X,"stop",D,d),be=dn(X,"stop",W=>{Qn(W.target)||ie(!1),v&&v(W)},!1),ee=Cp(W=>{Z.current||(Z.current=W.currentTarget),Qn(W.target)&&(ie(!0),g&&g(W)),y&&y(W)}),B=()=>{let W=Z.current;return W?W.tagName==="BUTTON"?!1:!(W.tagName==="A"&&W.href):l&&l!=="button"},se=Cp(W=>{c&&!W.repeat&&te&&W.key===" "&&X.stop(W,()=>{X.start(W)}),W.target===W.currentTarget&&B()&&W.key===" "&&W.preventDefault(),S&&S(W),W.target===W.currentTarget&&B()&&W.key==="Enter"&&!p&&(W.preventDefault(),x&&x(W))}),xe=Cp(W=>{c&&W.key===" "&&te&&!W.defaultPrevented&&X.stop(W,()=>{X.pulsate(W)}),P&&P(W),x&&W.target===W.currentTarget&&B()&&W.key===" "&&!W.defaultPrevented&&!p&&x(W)}),he=l;he==="button"&&(Y.href||Y.to)&&(he=b);let Ne={};if(he==="button"){let W=!!Y.formAction;Ne.type=k===void 0&&!W?"button":k,Ne.disabled=p}else!Y.href&&!Y.to&&(Ne.role="button"),p&&(Ne["aria-disabled"]=p);let et=Tt(o,Z),Qt={...r,centerRipple:a,component:l,disabled:p,disableRipple:f,disableTouchRipple:d,focusRipple:c,tabIndex:A,focusVisible:te},rt=bM(Qt);return(0,Ff.jsxs)(vM,{as:he,className:j(rt.root,s),owne
Line truncated
|
||||
`,vM=Ct.forwardRef(function(t,o){let r=H({props:t,name:"MuiTouchRipple"}),{center:n=!1,classes:a={},className:i,...s}=r,[l,p]=Ct.useState([]),f=Ct.useRef(0),d=Ct.useRef(null);Ct.useEffect(()=>{d.current&&(d.current(),d.current=null)},[l]);let c=Ct.useRef(!1),u=Zn(),b=Ct.useRef(null),v=Ct.useRef(null),x=Ct.useCallback(g=>{let{pulsate:S,rippleX:P,rippleY:E,rippleSize:R,cb:N}=g;p(O=>[...O,(0,Gf.jsx)(bM,{classes:{ripple:j(a.ripple,jo.ripple),rippleVisible:j(a.rippleVisible,jo.rippleVisible),ripplePulsate:j(a.ripplePulsate,jo.ripplePulsate),child:j(a.child,jo.child),childLeaving:j(a.childLeaving,jo.childLeaving),childPulsate:j(a.childPulsate,jo.childPulsate)},timeout:Vh,pulsate:S,rippleX:P,rippleY:E,rippleSize:R},f.current)]),f.current+=1,d.current=N},[a]),m=Ct.useCallback((g={},S={},P=()=>{})=>{let{pulsate:E=!1,center:R=n||S.pulsate,fakeElement:N=!1}=S;if(g?.type==="mousedown"&&c.current){c.current=!1;return}g?.type==="touchstart"&&(c.current=!0);let O=N?null:v.current,D=O?O.getBoundingClientRect():{width:0,height:0,left:0,top:0},T,A,M;if(R||g===void 0||g.clientX===0&&g.clientY===0||!g.clientX&&!g.touches)T=Math.round(D.width/2),A=Math.round(D.height/2);else{let{clientX:U,clientY:L}=g.touches&&g.touches.length>0?g.touches[0]:g;T=Math.round(U-D.left),A=Math.round(L-D.top)}if(R)M=Math.sqrt((2*D.width**2+D.height**2)/3),M%2===0&&(M+=1);else{let U=Math.max(Math.abs((O?O.clientWidth:0)-T),T)*2+2,L=Math.max(Math.abs((O?O.clientHeight:0)-A),A)*2+2;M=Math.sqrt(U**2+L**2)}g?.touches?b.current===null&&(b.current=()=>{x({pulsate:E,rippleX:T,rippleY:A,rippleSize:M,cb:P})},u.start(mM,()=>{b.current&&(b.current(),b.current=null)})):x({pulsate:E,rippleX:T,rippleY:A,rippleSize:M,cb:P})},[n,x,u]),h=Ct.useCallback(()=>{m({},{pulsate:!0})},[m]),y=Ct.useCallback((g,S)=>{if(u.clear(),g?.type==="touchend"&&b.current){b.current(),b.current=null,u.start(0,()=>{y(g,S)});return}b.current=null,p(P=>P.length>0?P.slice(1):P),d.current=S},[u]);return Ct.useImperativeHandle(o,()=>({pulsate:h,start:m,stop:y}),[h,m,y]),(0,Gf.jsx)(TM,{className:j(jo.root,a.root,i),ref:v,...s,children:(0,Gf.jsx)(zh,{component:null,exit:!0,children:l})})}),V1=vM;function H1(e){return I("MuiButtonBase",e)}var xM=F("MuiButtonBase",["root","disabled","focusVisible"]),F1=xM;var Yf=C(k(),1),SM=e=>{let{disabled:t,focusVisible:o,focusVisibleClassName:r,classes:n}=e,i=V({root:["root",t&&"disabled",o&&"focusVisible"]},H1,n);return o&&r&&(i.root+=` ${r}`),i},PM=w("button",{name:"MuiButtonBase",slot:"Root"})({display:"inline-flex",alignItems:"center",justifyContent:"center",position:"relative",boxSizing:"border-box",WebkitTapHighlightColor:"transparent",backgroundColor:"transparent",outline:0,border:0,margin:0,borderRadius:0,padding:0,cursor:"pointer",userSelect:"none",verticalAlign:"middle",MozAppearance:"none",WebkitAppearance:"none",textDecoration:"none",color:"inherit","&::-moz-focus-inner":{borderStyle:"none"},[`&.${F1.disabled}`]:{pointerEvents:"none",cursor:"default"},"@media print":{colorAdjust:"exact"}}),CM=kr.forwardRef(function(t,o){let r=H({props:t,name:"MuiButtonBase"}),{action:n,centerRipple:a=!1,children:i,className:s,component:l="button",disabled:p=!1,disableRipple:f=!1,disableTouchRipple:d=!1,focusRipple:c=!1,focusVisibleClassName:u,LinkComponent:b="a",onBlur:v,onClick:x,onContextMenu:m,onDragLeave:h,onFocus:y,onFocusVisible:g,onKeyDown:S,onKeyUp:P,onMouseDown:E,onMouseLeave:R,onMouseUp:N,onTouchEnd:O,onTouchMove:D,onTouchStart:T,tabIndex:A=0,TouchRippleProps:M,touchRippleRef:U,type:L,...G}=r,J=kr.useRef(null),K=$f(),he=bt(K.ref,U),[re,se]=kr.useState(!1);p&&re&&se(!1),kr.useImperativeHandle(n,()=>({focusVisible:()=>{se(!0),J.current.focus()}}),[]);let ie=K.shouldMount&&!f&&!p;kr.useEffect(()=>{re&&c&&!f&&K.pulsate()},[f,c,re,K]);let Xe=hn(K,"start",E,d),Ne=hn(K,"stop",m,d),Ce=hn(K,"stop",h,d),me=hn(K,"stop",N,d),ot=hn(K,"stop",ee=>{re&&ee.preventDefault(),R&&R(ee)},d),ge=hn(K,"start",T,d),oe=hn(K,"stop",O,d),X=hn(K,"stop",D,d),Q=hn(K,"stop",ee=>{Jn(ee.target)||se(!1),v&&v(ee)},!1),Ee=wp(ee=>{J.current||(J.current=ee.currentTarget),Jn(ee.target)&&(se(!0),g&&g(ee)),y&&y(ee)}),Y=()=>{let ee=J.current;return ee?ee.tagName==="BUTTON"?!1:!(ee.tagName==="A"&&ee.href):l&&l!=="button"},ce=wp(ee=>{c&&!ee.repeat&&re&&ee.key===" "&&K.stop(ee,()=>{K.start(ee)}),ee.target===ee.currentTarget&&Y()&&ee.key===" "&&ee.preventDefault(),S&&S(ee),ee.target===ee.currentTarget&&Y()&&ee.key==="Enter"&&!p&&(ee.preventDefault(),x&&x(ee))}),we=wp(ee=>{c&&ee.key===" "&&re&&!ee.defaultPrevented&&K.stop(ee,()=>{K.pulsate(ee)}),P&&P(ee),x&&ee.target===ee.currentTarget&&Y()&&ee.key===" "&&!ee.defaultPrevented&&!p&&x(ee)}),Te=l;Te==="button"&&(G.href||G.to)&&(Te=b);let Ae={};if(Te==="button"){let ee=!!G.formAction;Ae.type=L===void 0&&!ee?"button":L,Ae.disabled=p}else!G.href&&!G.to&&(Ae.role="button"),p&&(Ae["aria-disabled"]=p);let et=bt(o,J),Qt={...r,centerRipple:a,component:l,disabled:p,disableRipple:f,disableTouchRipple:d,focusRipple:c,tabIndex:A,focusVisible:re},rt=SM(Qt);return(0,Yf.j
Line truncated
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
@@ -122,7 +122,7 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
`,Hh=ho`
|
||||
`,$h=To`
|
||||
0% {
|
||||
stroke-dasharray: 1px, 200px;
|
||||
stroke-dashoffset: 0;
|
||||
@@ -137,13 +137,13 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
stroke-dasharray: 1px, 200px;
|
||||
stroke-dashoffset: -126px;
|
||||
}
|
||||
`,MM=typeof Vh!="string"?hr`
|
||||
animation: ${Vh} 1.4s linear infinite;
|
||||
`:null,_M=typeof Hh!="string"?hr`
|
||||
animation: ${Hh} 1.4s ease-in-out infinite;
|
||||
`:null,DM=e=>{let{classes:t,variant:o,color:r,disableShrink:n}=e,a={root:["root",o,`color${q(r)}`],svg:["svg"],track:["track"],circle:["circle",`circle${q(o)}`,n&&"circleDisableShrink"]};return H(a,$1,t)},zM=w("span",{name:"MuiCircularProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[o.variant],t[`color${q(o.color)}`]]}})(G(({theme:e})=>({display:"inline-block",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("transform")}},{props:{variant:"indeterminate"},style:MM||{animation:`${Vh} 1.4s linear infinite`}},...Object.entries(e.palette).filter(_e()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}}))]}))),jM=w("svg",{name:"MuiCircularProgress",slot:"Svg"})({display:"block"}),UM=w("circle",{name:"MuiCircularProgress",slot:"Circle",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.circle,t[`circle${q(o.variant)}`],o.disableShrink&&t.circleDisableShrink]}})(G(({theme:e})=>({stroke:"currentColor",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("stroke-dashoffset")}},{props:{variant:"indeterminate"},style:{strokeDasharray:"80px, 200px",strokeDashoffset:0}},{props:({ownerState:t})=>t.variant==="indeterminate"&&!t.disableShrink,style:_M||{animation:`${Hh} 1.4s ease-in-out infinite`}}]}))),BM=w("circle",{name:"MuiCircularProgress",slot:"Track"})(G(({theme:e})=>({stroke:"currentColor",opacity:(e.vars||e).palette.action.activatedOpacity}))),LM=q1.forwardRef(function(t,o){let r=F({props:t,name:"MuiCircularProgress"}),{className:n,color:a="primary",disableShrink:i=!1,enableTrackSlot:s=!1,size:l=40,style:p,thickness:f=3.6,value:d=0,variant:c="indeterminate",...u}=r,b={...r,color:a,disableShrink:i,size:l,thickness:f,value:d,variant:c,enableTrackSlot:s},v=DM(b),x={},m={},h={};if(c==="determinate"){let y=2*Math.PI*((xr-f)/2);x.strokeDasharray=y.toFixed(3),h["aria-valuenow"]=Math.round(d),x.strokeDashoffset=`${((100-d)/100*y).toFixed(3)}px`,m.transform="rotate(-90deg)"}return(0,Ds.jsx)(zM,{className:j(v.root,n),style:{width:l,height:l,...m,...p},ownerState:b,ref:o,role:"progressbar",...h,...u,children:(0,Ds.jsxs)(jM,{className:v.svg,ownerState:b,viewBox:`${xr/2} ${xr/2} ${xr} ${xr}`,children:[s?(0,Ds.jsx)(BM,{className:v.track,ownerState:b,cx:xr,cy:xr,r:(xr-f)/2,fill:"none",strokeWidth:f,"aria-hidden":"true"}):null,(0,Ds.jsx)(UM,{className:v.circle,style:x,ownerState:b,cx:xr,cy:xr,r:(xr-f)/2,fill:"none",strokeWidth:f})]})})}),Zn=LM;function G1(e){return V("MuiIconButton",e)}var kM=$("MuiIconButton",["root","disabled","colorInherit","colorPrimary","colorSecondary","colorError","colorInfo","colorSuccess","colorWarning","edgeStart","edgeEnd","sizeSmall","sizeMedium","sizeLarge","loading","loadingIndicator","loadingWrapper"]),Fh=kM;var zs=C(I(),1),IM=e=>{let{classes:t,disabled:o,color:r,edge:n,size:a,loading:i}=e,s={root:["root",i&&"loading",o&&"disabled",r!=="default"&&`color${q(r)}`,n&&`edge${q(n)}`,`size${q(a)}`],loadingIndicator:["loadingIndicator"],loadingWrapper:["loadingWrapper"]};return H(s,G1,t)},VM=w(mn,{name:"MuiIconButton",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,o.loading&&t.loading,o.color!=="default"&&t[`color${q(o.color)}`],o.edge&&t[`edge${q(o.edge)}`],t[`size${q(o.size)}`]]}})(G(({theme:e})=>({textAlign:"center",flex:"0 0 auto",fontSize:e.typography.pxToRem(24),padding:8,borderRadius:"50%",color:(e.vars||e).palette.action.active,transition:e.transitions.create("background-color",{duration:e.transitions.duration.shortest}),variants:[{props:t=>!t.disableRipple,style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette.action.active,(e.vars||e).palette.action.hoverOpacity),"&:hover":{backgroundColor:"var(--IconButton-hoverBg)","@media (hover: none)":{backgroundColor:"transparent"}}}},{props:{edge:"start"},style:{marginLeft:-12}},{props:{edge:"start",size:"small"},style:{marginLeft:-3}},{props:{edge:"end"},style:{marginRight:-12}},{props:{edge:"end",size:"small"},style:{marginRight:-3}}]})),G(({theme:e})=>({variants:[{props:{color:"inherit"},style:{color:"inherit"}},...Object.entries(e.palette).filter(_e()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}})),...Object.entries(e.palette).filter(_e()).map(([t])=>({props:{color:t},style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette[t].main,(e.vars||e).palette.action.hoverOpacity)}})),{props:{size:"small"},style:{padding:5,fontSize:e.typography.pxToRem(18)}},{props:{size:"large"},style:{padding:12,fontSize:e.typography.pxToRem(28)}}],[`&.${Fh.disabled}`]:{backgroundColor:"transparent",color:(e.vars||e).palette.action.disabled},[`&.${Fh.loading}`]:{color:"transparent"}}))),HM=w("span",{name:"MuiIconButton",slot:"LoadingIndicator"})(({theme:e})=>({display:"none",position:"absolute",visibility:"visible",top:"50%",left:"50%",transform:"translate(-50%, -50%)",color:(e.vars||e).palette.action.disabled,variants:[{props:{loading:!0},style:{display:"flex"}}]})),FM=Gf.forwardRef(function(t,o){
Line truncated
|
||||
`&&(g.value+=" ");let E=P.boxSizing,R=Kf(P.paddingBottom)+Kf(P.paddingTop),N=Kf(P.borderBottomWidth)+Kf(P.borderTopWidth),O=g.scrollHeight;g.value="x";let D=g.scrollHeight,T=O;a&&(T=Math.max(Number(a)*D,T)),n&&(T=Math.min(Number(n)*D,T)),T=Math.max(T,D);let A=T+(E==="border-box"?R+N:0),M=Math.abs(T-O)<=1;return{outerHeightStyle:A,overflowing:M}},[n,a,t.placeholder]),v=Gn(()=>{let y=f.current,g=b();if(!y||!g||cS(g))return!1;let S=g.outerHeightStyle;return c.current!=null&&c.current!==S}),x=jo.useCallback(()=>{let y=f.current,g=b();if(!y||!g||cS(g))return;let S=g.outerHeightStyle;c.current!==S&&(c.current=S,y.style.height=`${S}px`),y.style.overflow=g.overflowing?"hidden":""},[b]),m=jo.useRef(-1);return so(()=>{let y=Es(x),g=f?.current;if(!g)return;let S=er(g);S.addEventListener("resize",y);let P;return typeof ResizeObserver<"u"&&(P=new ResizeObserver(()=>{v()&&(P.unobserve(g),cancelAnimationFrame(m.current),x(),m.current=requestAnimationFrame(()=>{P.observe(g)}))}),P.observe(g)),()=>{y.clear(),cancelAnimationFrame(m.current),S.removeEventListener("resize",y),P&&P.disconnect()}},[b,x,v]),so(()=>{x()}),(0,Bp.jsxs)(jo.Fragment,{children:[(0,Bp.jsx)("textarea",{value:s,onChange:y=>{p||x();let g=y.target,S=g.value.length,P=g.value.endsWith(`
|
||||
`),E=g.selectionStart===S;P&&E&&g.setSelectionRange(S,S),r&&r(y)},ref:d,rows:a,style:i,...l}),(0,Bp.jsx)("textarea",{"aria-hidden":!0,className:t.className,readOnly:!0,ref:u,tabIndex:-1,style:{...a4.shadow,...i,paddingTop:0,paddingBottom:0}})]})}),Gh=s4;function Uo({props:e,states:t,muiFormControl:o}){return t.reduce((r,n)=>(r[n]=e[n],o&&typeof e[n]>"u"&&(r[n]=o[n]),r),{})}var fS=C(L(),1),l4=fS.createContext(void 0),Wn=l4;var dS=C(L(),1);function uo(){return dS.useContext(Wn)}function Qf(e){let t=e.activeElement;for(;t?.shadowRoot?.activeElement!=null;)t=t.shadowRoot.activeElement;return t}var gn=Qf;function mS(e){return e!=null&&!(Array.isArray(e)&&e.length===0)}function ii(e,t=!1){return e&&(mS(e.value)&&e.value!==""||t&&mS(e.defaultValue)&&e.defaultValue!=="")}function yS(e){return e.startAdornment}function hS(e){return V("MuiInputBase",e)}var p4=$("MuiInputBase",["root","formControl","focused","disabled","adornedStart","adornedEnd","error","sizeSmall","multiline","colorSecondary","fullWidth","hiddenLabel","readOnly","input","inputSizeSmall","inputMultiline","inputTypeSearch","inputAdornedStart","inputAdornedEnd","inputHiddenLabel"]),Sr=p4;var si=C(I(),1),gS,Yh="mui-auto-fill",Zf="mui-auto-fill-cancel",li=(e,t)=>{let{ownerState:o}=e;return[t.root,o.formControl&&t.formControl,o.startAdornment&&t.adornedStart,o.endAdornment&&t.adornedEnd,o.error&&t.error,o.size==="small"&&t.sizeSmall,o.multiline&&t.multiline,o.color&&t[`color${q(o.color)}`],o.fullWidth&&t.fullWidth,o.hiddenLabel&&t.hiddenLabel]},pi=(e,t)=>{let{ownerState:o}=e;return[t.input,o.size==="small"&&t.inputSizeSmall,o.multiline&&t.inputMultiline,o.type==="search"&&t.inputTypeSearch,o.startAdornment&&t.inputAdornedStart,o.endAdornment&&t.inputAdornedEnd,o.hiddenLabel&&t.inputHiddenLabel]},u4=e=>{let{classes:t,color:o,disabled:r,error:n,endAdornment:a,focused:i,formControl:s,fullWidth:l,hiddenLabel:p,multiline:f,readOnly:d,size:c,startAdornment:u,type:b}=e,v={root:["root",`color${q(o)}`,r&&"disabled",n&&"error",l&&"fullWidth",i&&"focused",s&&"formControl",c&&c!=="medium"&&`size${q(c)}`,f&&"multiline",u&&"adornedStart",a&&"adornedEnd",p&&"hiddenLabel",d&&"readOnly"],input:["input",r&&"disabled",b==="search"&&"inputTypeSearch",f&&"inputMultiline",c==="small"&&"inputSizeSmall",p&&"inputHiddenLabel",u&&"inputAdornedStart",a&&"inputAdornedEnd",d&&"readOnly"]};return H(v,hS,t)},ui=w("div",{name:"MuiInputBase",slot:"Root",overridesResolver:li})(G(({theme:e})=>({...e.typography.body1,color:(e.vars||e).palette.text.primary,lineHeight:"1.4375em",boxSizing:"border-box",position:"relative",cursor:"text",display:"inline-flex",alignItems:"center",[`&.${Sr.disabled}`]:{color:(e.vars||e).palette.text.disabled,cursor:"default"},variants:[{props:({ownerState:t})=>t.multiline,style:{padding:"4px 0 5px"}},{props:({ownerState:t,size:o})=>t.multiline&&o==="small",style:{paddingTop:1}},{props:({ownerState:t})=>t.fullWidth,style:{width:"100%"}}]}))),ci=w("input",{name:"MuiInputBase",slot:"Input",overridesResolver:pi})(G(({theme:e})=>{let t=e.palette.mode==="light",o={color:"currentColor",...e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5},transition:e.transitions.create("opacity",{duration:e.transitions.duration.shorter})},r={opacity:"0 !important"},n=e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5};return{font:"inherit",letterSpacing:"inherit",color:"currentColor",padding:"4px 0 5px",border:0,boxSizing:"content-box",background:"none",height:"1.4375em",margin:0,WebkitTapHighlightColor:"transparent",display:"block",minWidth:0,width:"100%","&::-webkit-input-placeholder":o,"&::-moz-placeholder":o,"&::-ms-input-placeholder":o,"&:focus":{outline:0},"&:invalid":{boxShadow:"none"},"&::-webkit-search-decoration":{WebkitAppearance:"none"},[`label[data-shrink=false] + .${Sr.formControl} &`]:{"&::-webkit-input-placeholder":r,"&::-moz-placeholder":r,"&::-ms-input-placeholder":r,"&:focus::-webkit-input-placeholder":n,"&:focus::-moz-placeholder":n,"&:focus::-ms-input-placeholder":n},[`&.${Sr.disabled}`]:{opacity:1,WebkitTextFillColor:(e.vars||e).palette.text.disabled},variants:[{props:({ownerState:a})=>!a.disableInjectingGlobalStyles,style:{animationName:Zf,animationDuration:"10ms","&:-webkit-autofill":{animationDuration:"5000s",animationName:Yh}}},{props:{size:"small"},style:{paddingTop:1}},{props:({ownerState:a})=>a.multiline,style:{height:"auto",resize:"none",padding:0,paddingTop:0}},{props:{type:"search"},style:{MozAppearance:"textfield"}}]}})),TS=vp({[`@keyframes ${Yh}`]:{from:{animationName:Yh}},[`@keyframes ${Zf}`]:{from:{animationName:Zf}}}),c4=Jt.forwardRef(function(t,o){let r=F({props:t,name:"MuiInputBase"}),{"aria-describedby":n,autoComplete:a,autoFocus:i,className:s,color:l,components:p={},componentsProps:f={},defaultValue:d,disabled:c,disableInjectingGlobalStyles:u,endAdornment:b,error:v,fullWidth:x=!1,id:m,inputComponent:h="input",inputProps:y={},inputRef:g,margin:S,maxRows:P,minRows:E,multiline:R=!1,name:N,onBlur:O,onChange:D,onClick
Line truncated
|
||||
`,zM=typeof Fh!="string"?Tr`
|
||||
animation: ${Fh} 1.4s linear infinite;
|
||||
`:null,jM=typeof $h!="string"?Tr`
|
||||
animation: ${$h} 1.4s ease-in-out infinite;
|
||||
`:null,UM=e=>{let{classes:t,variant:o,color:r,disableShrink:n}=e,a={root:["root",o,`color${$(r)}`],svg:["svg"],track:["track"],circle:["circle",`circle${$(o)}`,n&&"circleDisableShrink"]};return V(a,G1,t)},BM=w("span",{name:"MuiCircularProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[o.variant],t[`color${$(o.color)}`]]}})(q(({theme:e})=>({display:"inline-block",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("transform")}},{props:{variant:"indeterminate"},style:zM||{animation:`${Fh} 1.4s linear infinite`}},...Object.entries(e.palette).filter(ze()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}}))]}))),LM=w("svg",{name:"MuiCircularProgress",slot:"Svg"})({display:"block"}),kM=w("circle",{name:"MuiCircularProgress",slot:"Circle",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.circle,t[`circle${$(o.variant)}`],o.disableShrink&&t.circleDisableShrink]}})(q(({theme:e})=>({stroke:"currentColor",variants:[{props:{variant:"determinate"},style:{transition:e.transitions.create("stroke-dashoffset")}},{props:{variant:"indeterminate"},style:{strokeDasharray:"80px, 200px",strokeDashoffset:0}},{props:({ownerState:t})=>t.variant==="indeterminate"&&!t.disableShrink,style:jM||{animation:`${$h} 1.4s ease-in-out infinite`}}]}))),IM=w("circle",{name:"MuiCircularProgress",slot:"Track"})(q(({theme:e})=>({stroke:"currentColor",opacity:(e.vars||e).palette.action.activatedOpacity}))),VM=Y1.forwardRef(function(t,o){let r=H({props:t,name:"MuiCircularProgress"}),{className:n,color:a="primary",disableShrink:i=!1,enableTrackSlot:s=!1,size:l=40,style:p,thickness:f=3.6,value:d=0,variant:c="indeterminate",...u}=r,b={...r,color:a,disableShrink:i,size:l,thickness:f,value:d,variant:c,enableTrackSlot:s},v=UM(b),x={},m={},h={};if(c==="determinate"){let y=2*Math.PI*((Pr-f)/2);x.strokeDasharray=y.toFixed(3),h["aria-valuenow"]=Math.round(d),x.strokeDashoffset=`${((100-d)/100*y).toFixed(3)}px`,m.transform="rotate(-90deg)"}return(0,Us.jsx)(BM,{className:j(v.root,n),style:{width:l,height:l,...m,...p},ownerState:b,ref:o,role:"progressbar",...h,...u,children:(0,Us.jsxs)(LM,{className:v.svg,ownerState:b,viewBox:`${Pr/2} ${Pr/2} ${Pr} ${Pr}`,children:[s?(0,Us.jsx)(IM,{className:v.track,ownerState:b,cx:Pr,cy:Pr,r:(Pr-f)/2,fill:"none",strokeWidth:f,"aria-hidden":"true"}):null,(0,Us.jsx)(kM,{className:v.circle,style:x,ownerState:b,cx:Pr,cy:Pr,r:(Pr-f)/2,fill:"none",strokeWidth:f})]})})}),ea=VM;function X1(e){return I("MuiIconButton",e)}var HM=F("MuiIconButton",["root","disabled","colorInherit","colorPrimary","colorSecondary","colorError","colorInfo","colorSuccess","colorWarning","edgeStart","edgeEnd","sizeSmall","sizeMedium","sizeLarge","loading","loadingIndicator","loadingWrapper"]),qh=HM;var Bs=C(k(),1),FM=e=>{let{classes:t,disabled:o,color:r,edge:n,size:a,loading:i}=e,s={root:["root",i&&"loading",o&&"disabled",r!=="default"&&`color${$(r)}`,n&&`edge${$(n)}`,`size${$(a)}`],loadingIndicator:["loadingIndicator"],loadingWrapper:["loadingWrapper"]};return V(s,X1,t)},$M=w(gn,{name:"MuiIconButton",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,o.loading&&t.loading,o.color!=="default"&&t[`color${$(o.color)}`],o.edge&&t[`edge${$(o.edge)}`],t[`size${$(o.size)}`]]}})(q(({theme:e})=>({textAlign:"center",flex:"0 0 auto",fontSize:e.typography.pxToRem(24),padding:8,borderRadius:"50%",color:(e.vars||e).palette.action.active,transition:e.transitions.create("background-color",{duration:e.transitions.duration.shortest}),variants:[{props:t=>!t.disableRipple,style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette.action.active,(e.vars||e).palette.action.hoverOpacity),"&:hover":{backgroundColor:"var(--IconButton-hoverBg)","@media (hover: none)":{backgroundColor:"transparent"}}}},{props:{edge:"start"},style:{marginLeft:-12}},{props:{edge:"start",size:"small"},style:{marginLeft:-3}},{props:{edge:"end"},style:{marginRight:-12}},{props:{edge:"end",size:"small"},style:{marginRight:-3}}]})),q(({theme:e})=>({variants:[{props:{color:"inherit"},style:{color:"inherit"}},...Object.entries(e.palette).filter(ze()).map(([t])=>({props:{color:t},style:{color:(e.vars||e).palette[t].main}})),...Object.entries(e.palette).filter(ze()).map(([t])=>({props:{color:t},style:{"--IconButton-hoverBg":e.alpha((e.vars||e).palette[t].main,(e.vars||e).palette.action.hoverOpacity)}})),{props:{size:"small"},style:{padding:5,fontSize:e.typography.pxToRem(18)}},{props:{size:"large"},style:{padding:12,fontSize:e.typography.pxToRem(28)}}],[`&.${qh.disabled}`]:{backgroundColor:"transparent",color:(e.vars||e).palette.action.disabled},[`&.${qh.loading}`]:{color:"transparent"}}))),qM=w("span",{name:"MuiIconButton",slot:"LoadingIndicator"})(({theme:e})=>({display:"none",position:"absolute",visibility:"visible",top:"50%",left:"50%",transform:"translate(-50%, -50%)",color:(e.vars||e).palette.action.disabled,variants:[{props:{loading:!0},style:{display:"flex"}}]})),GM=Qf.forwardRef(function(t,o){
Line truncated
|
||||
`&&(g.value+=" ");let E=P.boxSizing,R=Jf(P.paddingBottom)+Jf(P.paddingTop),N=Jf(P.borderBottomWidth)+Jf(P.borderTopWidth),O=g.scrollHeight;g.value="x";let D=g.scrollHeight,T=O;a&&(T=Math.max(Number(a)*D,T)),n&&(T=Math.min(Number(n)*D,T)),T=Math.max(T,D);let A=T+(E==="border-box"?R+N:0),M=Math.abs(T-O)<=1;return{outerHeightStyle:A,overflowing:M}},[n,a,t.placeholder]),v=Kn(()=>{let y=f.current,g=b();if(!y||!g||dS(g))return!1;let S=g.outerHeightStyle;return c.current!=null&&c.current!==S}),x=Bo.useCallback(()=>{let y=f.current,g=b();if(!y||!g||dS(g))return;let S=g.outerHeightStyle;c.current!==S&&(c.current=S,y.style.height=`${S}px`),y.style.overflow=g.overflowing?"hidden":""},[b]),m=Bo.useRef(-1);return so(()=>{let y=Ns(x),g=f?.current;if(!g)return;let S=tr(g);S.addEventListener("resize",y);let P;return typeof ResizeObserver<"u"&&(P=new ResizeObserver(()=>{v()&&(P.unobserve(g),cancelAnimationFrame(m.current),x(),m.current=requestAnimationFrame(()=>{P.observe(g)}))}),P.observe(g)),()=>{y.clear(),cancelAnimationFrame(m.current),S.removeEventListener("resize",y),P&&P.disconnect()}},[b,x,v]),so(()=>{x()}),(0,Hp.jsxs)(Bo.Fragment,{children:[(0,Hp.jsx)("textarea",{value:s,onChange:y=>{p||x();let g=y.target,S=g.value.length,P=g.value.endsWith(`
|
||||
`),E=g.selectionStart===S;P&&E&&g.setSelectionRange(S,S),r&&r(y)},ref:d,rows:a,style:i,...l}),(0,Hp.jsx)("textarea",{"aria-hidden":!0,className:t.className,readOnly:!0,ref:u,tabIndex:-1,style:{...l4.shadow,...i,paddingTop:0,paddingBottom:0}})]})}),Xh=u4;function Lo({props:e,states:t,muiFormControl:o}){return t.reduce((r,n)=>(r[n]=e[n],o&&typeof e[n]>"u"&&(r[n]=o[n]),r),{})}var mS=C(B(),1),c4=mS.createContext(void 0),ta=c4;var yS=C(B(),1);function co(){return yS.useContext(ta)}function ed(e){let t=e.activeElement;for(;t?.shadowRoot?.activeElement!=null;)t=t.shadowRoot.activeElement;return t}var bn=ed;function hS(e){return e!=null&&!(Array.isArray(e)&&e.length===0)}function pi(e,t=!1){return e&&(hS(e.value)&&e.value!==""||t&&hS(e.defaultValue)&&e.defaultValue!=="")}function gS(e){return e.startAdornment}function TS(e){return I("MuiInputBase",e)}var f4=F("MuiInputBase",["root","formControl","focused","disabled","adornedStart","adornedEnd","error","sizeSmall","multiline","colorSecondary","fullWidth","hiddenLabel","readOnly","input","inputSizeSmall","inputMultiline","inputTypeSearch","inputAdornedStart","inputAdornedEnd","inputHiddenLabel"]),Cr=f4;var ui=C(k(),1),bS,Kh="mui-auto-fill",td="mui-auto-fill-cancel",ci=(e,t)=>{let{ownerState:o}=e;return[t.root,o.formControl&&t.formControl,o.startAdornment&&t.adornedStart,o.endAdornment&&t.adornedEnd,o.error&&t.error,o.size==="small"&&t.sizeSmall,o.multiline&&t.multiline,o.color&&t[`color${$(o.color)}`],o.fullWidth&&t.fullWidth,o.hiddenLabel&&t.hiddenLabel]},fi=(e,t)=>{let{ownerState:o}=e;return[t.input,o.size==="small"&&t.inputSizeSmall,o.multiline&&t.inputMultiline,o.type==="search"&&t.inputTypeSearch,o.startAdornment&&t.inputAdornedStart,o.endAdornment&&t.inputAdornedEnd,o.hiddenLabel&&t.inputHiddenLabel]},d4=e=>{let{classes:t,color:o,disabled:r,error:n,endAdornment:a,focused:i,formControl:s,fullWidth:l,hiddenLabel:p,multiline:f,readOnly:d,size:c,startAdornment:u,type:b}=e,v={root:["root",`color${$(o)}`,r&&"disabled",n&&"error",l&&"fullWidth",i&&"focused",s&&"formControl",c&&c!=="medium"&&`size${$(c)}`,f&&"multiline",u&&"adornedStart",a&&"adornedEnd",p&&"hiddenLabel",d&&"readOnly"],input:["input",r&&"disabled",b==="search"&&"inputTypeSearch",f&&"inputMultiline",c==="small"&&"inputSizeSmall",p&&"inputHiddenLabel",u&&"inputAdornedStart",a&&"inputAdornedEnd",d&&"readOnly"]};return V(v,TS,t)},di=w("div",{name:"MuiInputBase",slot:"Root",overridesResolver:ci})(q(({theme:e})=>({...e.typography.body1,color:(e.vars||e).palette.text.primary,lineHeight:"1.4375em",boxSizing:"border-box",position:"relative",cursor:"text",display:"inline-flex",alignItems:"center",[`&.${Cr.disabled}`]:{color:(e.vars||e).palette.text.disabled,cursor:"default"},variants:[{props:({ownerState:t})=>t.multiline,style:{padding:"4px 0 5px"}},{props:({ownerState:t,size:o})=>t.multiline&&o==="small",style:{paddingTop:1}},{props:({ownerState:t})=>t.fullWidth,style:{width:"100%"}}]}))),mi=w("input",{name:"MuiInputBase",slot:"Input",overridesResolver:fi})(q(({theme:e})=>{let t=e.palette.mode==="light",o={color:"currentColor",...e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5},transition:e.transitions.create("opacity",{duration:e.transitions.duration.shorter})},r={opacity:"0 !important"},n=e.vars?{opacity:e.vars.opacity.inputPlaceholder}:{opacity:t?.42:.5};return{font:"inherit",letterSpacing:"inherit",color:"currentColor",padding:"4px 0 5px",border:0,boxSizing:"content-box",background:"none",height:"1.4375em",margin:0,WebkitTapHighlightColor:"transparent",display:"block",minWidth:0,width:"100%","&::-webkit-input-placeholder":o,"&::-moz-placeholder":o,"&::-ms-input-placeholder":o,"&:focus":{outline:0},"&:invalid":{boxShadow:"none"},"&::-webkit-search-decoration":{WebkitAppearance:"none"},[`label[data-shrink=false] + .${Cr.formControl} &`]:{"&::-webkit-input-placeholder":r,"&::-moz-placeholder":r,"&::-ms-input-placeholder":r,"&:focus::-webkit-input-placeholder":n,"&:focus::-moz-placeholder":n,"&:focus::-ms-input-placeholder":n},[`&.${Cr.disabled}`]:{opacity:1,WebkitTextFillColor:(e.vars||e).palette.text.disabled},variants:[{props:({ownerState:a})=>!a.disableInjectingGlobalStyles,style:{animationName:td,animationDuration:"10ms","&:-webkit-autofill":{animationDuration:"5000s",animationName:Kh}}},{props:{size:"small"},style:{paddingTop:1}},{props:({ownerState:a})=>a.multiline,style:{height:"auto",resize:"none",padding:0,paddingTop:0}},{props:{type:"search"},style:{MozAppearance:"textfield"}}]}})),vS=Ep({[`@keyframes ${Kh}`]:{from:{animationName:Kh}},[`@keyframes ${td}`]:{from:{animationName:td}}}),m4=Jt.forwardRef(function(t,o){let r=H({props:t,name:"MuiInputBase"}),{"aria-describedby":n,autoComplete:a,autoFocus:i,className:s,color:l,components:p={},componentsProps:f={},defaultValue:d,disabled:c,disableInjectingGlobalStyles:u,endAdornment:b,error:v,fullWidth:x=!1,id:m,inputComponent:h="input",inputProps:y={},inputRef:g,margin:S,maxRows:P,minRows:E,multiline:R=!1,name:N,onBlur:O,onChange:D,onClick
Line truncated
|
||||
0% {
|
||||
left: -35%;
|
||||
right: 100%;
|
||||
@@ -158,9 +158,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
left: 100%;
|
||||
right: -90%;
|
||||
}
|
||||
`,oD=typeof dg!="string"?hr`
|
||||
animation: ${dg} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
`:null,mg=ho`
|
||||
`,aD=typeof yg!="string"?Tr`
|
||||
animation: ${yg} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite;
|
||||
`:null,hg=To`
|
||||
0% {
|
||||
left: -200%;
|
||||
right: 100%;
|
||||
@@ -175,9 +175,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
left: 107%;
|
||||
right: -8%;
|
||||
}
|
||||
`,rD=typeof mg!="string"?hr`
|
||||
animation: ${mg} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite;
|
||||
`:null,yg=ho`
|
||||
`,iD=typeof hg!="string"?Tr`
|
||||
animation: ${hg} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite;
|
||||
`:null,gg=To`
|
||||
0% {
|
||||
opacity: 1;
|
||||
background-position: 0 -23px;
|
||||
@@ -192,9 +192,9 @@ To suppress this warning, you need to explicitly provide the \`palette.${t}Chann
|
||||
opacity: 1;
|
||||
background-position: -200px -23px;
|
||||
}
|
||||
`,nD=typeof yg!="string"?hr`
|
||||
animation: ${yg} 3s infinite linear;
|
||||
`:null,aD=e=>{let{classes:t,variant:o,color:r}=e,n={root:["root",`color${q(r)}`,o],dashed:["dashed",`dashedColor${q(r)}`],bar1:["bar","bar1",`barColor${q(r)}`,(o==="indeterminate"||o==="query")&&"bar1Indeterminate",o==="determinate"&&"bar1Determinate",o==="buffer"&&"bar1Buffer"],bar2:["bar","bar2",o!=="buffer"&&`barColor${q(r)}`,o==="buffer"&&`color${q(r)}`,(o==="indeterminate"||o==="query")&&"bar2Indeterminate",o==="buffer"&&"bar2Buffer"]};return H(n,PP,t)},hg=(e,t)=>e.vars?e.vars.palette.LinearProgress[`${t}Bg`]:e.palette.mode==="light"?e.lighten(e.palette[t].main,.62):e.darken(e.palette[t].main,.5),iD=w("span",{name:"MuiLinearProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[`color${q(o.color)}`],t[o.variant]]}})(G(({theme:e})=>({position:"relative",overflow:"hidden",display:"block",height:4,zIndex:0,"@media print":{colorAdjust:"exact"},variants:[...Object.entries(e.palette).filter(_e()).map(([t])=>({props:{color:t},style:{backgroundColor:hg(e,t)}})),{props:({ownerState:t})=>t.color==="inherit"&&t.variant!=="buffer",style:{"&::before":{content:'""',position:"absolute",left:0,top:0,right:0,bottom:0,backgroundColor:"currentColor",opacity:.3}}},{props:{variant:"buffer"},style:{backgroundColor:"transparent"}},{props:{variant:"query"},style:{transform:"rotate(180deg)"}}]}))),sD=w("span",{name:"MuiLinearProgress",slot:"Dashed",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.dashed,t[`dashedColor${q(o.color)}`]]}})(G(({theme:e})=>({position:"absolute",marginTop:0,height:"100%",width:"100%",backgroundSize:"10px 10px",backgroundPosition:"0 -23px",variants:[{props:{color:"inherit"},style:{opacity:.3,backgroundImage:"radial-gradient(currentColor 0%, currentColor 16%, transparent 42%)"}},...Object.entries(e.palette).filter(_e()).map(([t])=>{let o=hg(e,t);return{props:{color:t},style:{backgroundImage:`radial-gradient(${o} 0%, ${o} 16%, transparent 42%)`}}})]})),nD||{animation:`${yg} 3s infinite linear`}),lD=w("span",{name:"MuiLinearProgress",slot:"Bar1",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar1,t[`barColor${q(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar1Indeterminate,o.variant==="determinate"&&t.bar1Determinate,o.variant==="buffer"&&t.bar1Buffer]}})(G(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[{props:{color:"inherit"},style:{backgroundColor:"currentColor"}},...Object.entries(e.palette).filter(_e()).map(([t])=>({props:{color:t},style:{backgroundColor:(e.vars||e).palette[t].main}})),{props:{variant:"determinate"},style:{transition:`transform .${fg}s linear`}},{props:{variant:"buffer"},style:{zIndex:1,transition:`transform .${fg}s linear`}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:oD||{animation:`${dg} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite`}}]}))),pD=w("span",{name:"MuiLinearProgress",slot:"Bar2",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar2,t[`barColor${q(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar2Indeterminate,o.variant==="buffer"&&t.bar2Buffer]}})(G(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[...Object.entries(e.palette).filter(_e()).map(([t])=>({props:{color:t},style:{"--LinearProgressBar2-barColor":(e.vars||e).palette[t].main}})),{props:({ownerState:t})=>t.variant!=="buffer"&&t.color!=="inherit",style:{backgroundColor:"var(--LinearProgressBar2-barColor, currentColor)"}},{props:({ownerState:t})=>t.variant!=="buffer"&&t.color==="inherit",style:{backgroundColor:"currentColor"}},{props:{color:"inherit"},style:{opacity:.3}},...Object.entries(e.palette).filter(_e()).map(([t])=>({props:{color:t,variant:"buffer"},style:{backgroundColor:hg(e,t),transition:`transform .${fg}s linear`}})),{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:rD||{animation:`${mg} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite`}}]}))),uD=CP.forwardRef(function(t,o){let r=F({props:t,name:"MuiLinearProgress"}),{className:n,color:a="primary",value:i,valueBuffer:s,variant:l="indeterminate",...p}=r,f={...r,color:a,variant:l},d=aD(f),c=sf(),u={},b={bar1:{},bar2:{}};if((l==="determinate"||l==="buffer")&&i!==void 0){u["aria-valuenow"]=Math.round(i),u["aria-valuemin"]=0,u["aria-valuemax"]=100;let v=i-100;c&&(v=-v),b.bar1.transform=`translateX(${v}%)`}if(l==="buffer"&&s!==void 0){let v=(s||0)-100;c&&(v=-v),b.bar2.transform=`translateX(${v}%)`}return(0,$s.jsxs)(iD,{className:j(d.root,n),ownerState:f,role:"progressbar",...u,ref:o,...p,children:[l==="buffer"?(0,$s.jsx)(sD,{className:d.dashed,ownerState:f}):null,(0,$s.jsx)(lD,{className:d.bar1,ownerState:f
Line truncated
|
||||
`,sD=typeof gg!="string"?Tr`
|
||||
animation: ${gg} 3s infinite linear;
|
||||
`:null,lD=e=>{let{classes:t,variant:o,color:r}=e,n={root:["root",`color${$(r)}`,o],dashed:["dashed",`dashedColor${$(r)}`],bar1:["bar","bar1",`barColor${$(r)}`,(o==="indeterminate"||o==="query")&&"bar1Indeterminate",o==="determinate"&&"bar1Determinate",o==="buffer"&&"bar1Buffer"],bar2:["bar","bar2",o!=="buffer"&&`barColor${$(r)}`,o==="buffer"&&`color${$(r)}`,(o==="indeterminate"||o==="query")&&"bar2Indeterminate",o==="buffer"&&"bar2Buffer"]};return V(n,EP,t)},Tg=(e,t)=>e.vars?e.vars.palette.LinearProgress[`${t}Bg`]:e.palette.mode==="light"?e.lighten(e.palette[t].main,.62):e.darken(e.palette[t].main,.5),pD=w("span",{name:"MuiLinearProgress",slot:"Root",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.root,t[`color${$(o.color)}`],t[o.variant]]}})(q(({theme:e})=>({position:"relative",overflow:"hidden",display:"block",height:4,zIndex:0,"@media print":{colorAdjust:"exact"},variants:[...Object.entries(e.palette).filter(ze()).map(([t])=>({props:{color:t},style:{backgroundColor:Tg(e,t)}})),{props:({ownerState:t})=>t.color==="inherit"&&t.variant!=="buffer",style:{"&::before":{content:'""',position:"absolute",left:0,top:0,right:0,bottom:0,backgroundColor:"currentColor",opacity:.3}}},{props:{variant:"buffer"},style:{backgroundColor:"transparent"}},{props:{variant:"query"},style:{transform:"rotate(180deg)"}}]}))),uD=w("span",{name:"MuiLinearProgress",slot:"Dashed",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.dashed,t[`dashedColor${$(o.color)}`]]}})(q(({theme:e})=>({position:"absolute",marginTop:0,height:"100%",width:"100%",backgroundSize:"10px 10px",backgroundPosition:"0 -23px",variants:[{props:{color:"inherit"},style:{opacity:.3,backgroundImage:"radial-gradient(currentColor 0%, currentColor 16%, transparent 42%)"}},...Object.entries(e.palette).filter(ze()).map(([t])=>{let o=Tg(e,t);return{props:{color:t},style:{backgroundImage:`radial-gradient(${o} 0%, ${o} 16%, transparent 42%)`}}})]})),sD||{animation:`${gg} 3s infinite linear`}),cD=w("span",{name:"MuiLinearProgress",slot:"Bar1",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar1,t[`barColor${$(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar1Indeterminate,o.variant==="determinate"&&t.bar1Determinate,o.variant==="buffer"&&t.bar1Buffer]}})(q(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[{props:{color:"inherit"},style:{backgroundColor:"currentColor"}},...Object.entries(e.palette).filter(ze()).map(([t])=>({props:{color:t},style:{backgroundColor:(e.vars||e).palette[t].main}})),{props:{variant:"determinate"},style:{transition:`transform .${mg}s linear`}},{props:{variant:"buffer"},style:{zIndex:1,transition:`transform .${mg}s linear`}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:aD||{animation:`${yg} 2.1s cubic-bezier(0.65, 0.815, 0.735, 0.395) infinite`}}]}))),fD=w("span",{name:"MuiLinearProgress",slot:"Bar2",overridesResolver:(e,t)=>{let{ownerState:o}=e;return[t.bar,t.bar2,t[`barColor${$(o.color)}`],(o.variant==="indeterminate"||o.variant==="query")&&t.bar2Indeterminate,o.variant==="buffer"&&t.bar2Buffer]}})(q(({theme:e})=>({width:"100%",position:"absolute",left:0,bottom:0,top:0,transition:"transform 0.2s linear",transformOrigin:"left",variants:[...Object.entries(e.palette).filter(ze()).map(([t])=>({props:{color:t},style:{"--LinearProgressBar2-barColor":(e.vars||e).palette[t].main}})),{props:({ownerState:t})=>t.variant!=="buffer"&&t.color!=="inherit",style:{backgroundColor:"var(--LinearProgressBar2-barColor, currentColor)"}},{props:({ownerState:t})=>t.variant!=="buffer"&&t.color==="inherit",style:{backgroundColor:"currentColor"}},{props:{color:"inherit"},style:{opacity:.3}},...Object.entries(e.palette).filter(ze()).map(([t])=>({props:{color:t,variant:"buffer"},style:{backgroundColor:Tg(e,t),transition:`transform .${mg}s linear`}})),{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:{width:"auto"}},{props:({ownerState:t})=>t.variant==="indeterminate"||t.variant==="query",style:iD||{animation:`${hg} 2.1s cubic-bezier(0.165, 0.84, 0.44, 1) 1.15s infinite`}}]}))),dD=RP.forwardRef(function(t,o){let r=H({props:t,name:"MuiLinearProgress"}),{className:n,color:a="primary",value:i,valueBuffer:s,variant:l="indeterminate",...p}=r,f={...r,color:a,variant:l},d=lD(f),c=cf(),u={},b={bar1:{},bar2:{}};if((l==="determinate"||l==="buffer")&&i!==void 0){u["aria-valuenow"]=Math.round(i),u["aria-valuemin"]=0,u["aria-valuemax"]=100;let v=i-100;c&&(v=-v),b.bar1.transform=`translateX(${v}%)`}if(l==="buffer"&&s!==void 0){let v=(s||0)-100;c&&(v=-v),b.bar2.transform=`translateX(${v}%)`}return(0,Xs.jsxs)(pD,{className:j(d.root,n),ownerState:f,role:"progressbar",...u,ref:o,...p,children:[l==="buffer"?(0,Xs.jsx)(uD,{className:d.dashed,ownerState:f}):null,(0,Xs.jsx)(cD,{className:d.bar1,ownerState:f
Line truncated
|
||||
/*! Bundled license information:
|
||||
|
||||
react/cjs/react.production.js:
|
||||
|
||||
Binary file not shown.
@@ -29,7 +29,7 @@
|
||||
<script src="/appearance.js?v=b178d8b94c59"></script>
|
||||
<title>XGift · Premium 兑换</title>
|
||||
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
||||
<script type="module" src="/app.js?v=9ef23665d26d"></script>
|
||||
<script type="module" src="/app.js?v=2c9bcd09f3d7"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
"time"
|
||||
"xgift/internal/checkout"
|
||||
"xgift/internal/vault"
|
||||
)
|
||||
@@ -26,7 +27,7 @@ func checkFixture(t *testing.T) *server {
|
||||
t.Fatal(e)
|
||||
}
|
||||
t.Cleanup(func() { v.Close() })
|
||||
return &server{vault: v, origin: "https://example.test", work: make(chan struct{}, 1), limits: map[string]limit{}}
|
||||
return &server{vault: v, origin: "https://example.test", work: make(chan struct{}, 1), checks: make(chan struct{}, 4), limits: map[string]limit{}}
|
||||
}
|
||||
|
||||
func fakeEligibility(t *testing.T, calls *int, id string, err error) {
|
||||
@@ -67,7 +68,7 @@ func TestEligibilityCheck(t *testing.T) {
|
||||
if w.Code != 200 || body["eligible"] != true || calls != 1 {
|
||||
t.Fatalf("status=%d body=%s calls=%d", w.Code, w.Body.String(), calls)
|
||||
}
|
||||
if len(s.work) != 0 {
|
||||
if len(s.work) != 0 || len(s.checks) != 0 {
|
||||
t.Fatal("worker slot leaked")
|
||||
}
|
||||
})
|
||||
@@ -102,7 +103,7 @@ func TestEligibilityCheck(t *testing.T) {
|
||||
if w.Code != 503 || !strings.Contains(msg, "检测") {
|
||||
t.Fatalf("status=%d body=%s", w.Code, w.Body.String())
|
||||
}
|
||||
if len(s.work) != 0 {
|
||||
if len(s.work) != 0 || len(s.checks) != 0 {
|
||||
t.Fatal("worker slot leaked")
|
||||
}
|
||||
})
|
||||
@@ -119,7 +120,7 @@ func TestEligibilityCheck(t *testing.T) {
|
||||
t.Fatalf("X called %d times for invalid input", calls)
|
||||
}
|
||||
})
|
||||
t.Run("busy worker returns 503 instead of queueing", func(t *testing.T) {
|
||||
t.Run("busy payment worker does not block checks", func(t *testing.T) {
|
||||
s := checkFixture(t)
|
||||
calls := 0
|
||||
fakeEligibility(t, &calls, "1234", nil)
|
||||
@@ -127,7 +128,7 @@ func TestEligibilityCheck(t *testing.T) {
|
||||
defer func() { <-s.work }()
|
||||
w := submitCheck(s, "someone")
|
||||
msg, _ := checkBody(t, w)["message"].(string)
|
||||
if w.Code != 503 || !strings.Contains(msg, "检测") || calls != 0 {
|
||||
if w.Code != 200 || !strings.Contains(msg, "可以") || calls != 1 || len(s.work) != 1 || len(s.checks) != 0 {
|
||||
t.Fatalf("status=%d body=%s calls=%d", w.Code, w.Body.String(), calls)
|
||||
}
|
||||
})
|
||||
@@ -157,3 +158,59 @@ func TestEligibilityCheck(t *testing.T) {
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestEligibilityChecksRunConcurrently(t *testing.T) {
|
||||
s := checkFixture(t)
|
||||
started := make(chan struct{}, cap(s.checks))
|
||||
release := make(chan struct{})
|
||||
done := make(chan *httptest.ResponseRecorder, cap(s.checks))
|
||||
original := eligibilityCheck
|
||||
eligibilityCheck = func(context.Context, *vault.Vault, string, int) (string, error) {
|
||||
started <- struct{}{}
|
||||
<-release
|
||||
return "1234", nil
|
||||
}
|
||||
t.Cleanup(func() { eligibilityCheck = original })
|
||||
released := false
|
||||
launched := 0
|
||||
defer func() {
|
||||
if !released {
|
||||
close(release)
|
||||
}
|
||||
for i := 0; i < launched; i++ {
|
||||
<-done
|
||||
}
|
||||
}()
|
||||
for i := 0; i < cap(s.checks); i++ {
|
||||
launched++
|
||||
go func() { done <- submitCheck(s, "someone") }()
|
||||
}
|
||||
for i := 0; i < cap(s.checks); i++ {
|
||||
select {
|
||||
case <-started:
|
||||
case <-time.After(3 * time.Second):
|
||||
t.Fatal("checks did not start concurrently")
|
||||
}
|
||||
}
|
||||
if len(s.work) != 0 {
|
||||
t.Fatal("checks occupied the payment worker")
|
||||
}
|
||||
if w := submitCheck(s, "someone"); w.Code != 503 {
|
||||
t.Fatalf("unbounded checks: %d", w.Code)
|
||||
}
|
||||
close(release)
|
||||
released = true
|
||||
for launched > 0 {
|
||||
w := <-done
|
||||
launched--
|
||||
if w.Code != 200 {
|
||||
t.Errorf("check failed: %d", w.Code)
|
||||
}
|
||||
}
|
||||
if len(s.checks) != 0 {
|
||||
t.Fatal("check slot leaked")
|
||||
}
|
||||
if w := submitCheck(s, "someone"); w.Code != 200 {
|
||||
t.Fatalf("slot not reusable: %d", w.Code)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package site
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// lookup finds one redemption code by its full value so the admin can answer
|
||||
// "where is this code and what happened to it" without paging through batches.
|
||||
func (s *server) lookup(w http.ResponseWriter, r *http.Request) {
|
||||
var q struct {
|
||||
Code string `json:"code"`
|
||||
}
|
||||
if !decode(w, r, &q) {
|
||||
return
|
||||
}
|
||||
q.Code = strings.ToUpper(strings.TrimSpace(q.Code))
|
||||
if !codePattern.MatchString(q.Code) {
|
||||
message(w, 400, "请填写 XG- 开头、后接 48 位十六进制字符(0-9、A-F)的完整兑换码。")
|
||||
return
|
||||
}
|
||||
var c codeRow
|
||||
e := s.db.QueryRow("SELECT id,hint,batch,months,status,username,message,created,updated,progress,COALESCE(folder_id,''),copyable FROM codes WHERE hash=?", hash(q.Code)).Scan(&c.ID, &c.Hint, &c.Batch, &c.Months, &c.Status, &c.Username, &c.Message, &c.Created, &c.Updated, &c.Progress, &c.Folder, &c.Copyable)
|
||||
if errors.Is(e, sql.ErrNoRows) {
|
||||
message(w, 404, "没有找到这个兑换码,请核对后重试。")
|
||||
return
|
||||
}
|
||||
if e != nil {
|
||||
message(w, 503, "暂时无法查询兑换码,请稍后重试。")
|
||||
return
|
||||
}
|
||||
reply(w, 200, c)
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package site
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func lookupRequest(s *server, body string) *httptest.ResponseRecorder {
|
||||
req := httptest.NewRequest("POST", "/api/admin/lookup", strings.NewReader(body))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
s.lookup(w, req)
|
||||
return w
|
||||
}
|
||||
|
||||
func TestLookupFindsCodeByFullValue(t *testing.T) {
|
||||
s := resumeFixture(t, "review", "created")
|
||||
if _, err := s.db.Exec("ALTER TABLE codes ADD COLUMN folder_id TEXT"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := s.db.Exec("ALTER TABLE codes ADD COLUMN copyable INTEGER DEFAULT 1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
w := lookupRequest(s, `{"code":"xg-`+strings.Repeat("a", 48)+`"}`)
|
||||
var row codeRow
|
||||
if err := json.Unmarshal(w.Body.Bytes(), &row); err != nil {
|
||||
t.Fatalf("invalid JSON %q: %v", w.Body.String(), err)
|
||||
}
|
||||
if w.Code != 200 || row.ID != "code1" || row.Hint != "AAAA" || row.Status != "review" || row.Username != "recipient" || row.Months != 6 || !row.Copyable {
|
||||
t.Fatalf("status=%d body=%s", w.Code, w.Body.String())
|
||||
}
|
||||
if strings.Contains(w.Body.String(), strings.Repeat("A", 48)) || strings.Contains(w.Body.String(), "1234") {
|
||||
t.Fatal("lookup leaked the full code or recipient id")
|
||||
}
|
||||
}
|
||||
|
||||
func TestLookupRejectsBadInput(t *testing.T) {
|
||||
s := resumeFixture(t, "review", "created")
|
||||
if _, err := s.db.Exec("ALTER TABLE codes ADD COLUMN folder_id TEXT"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, err := s.db.Exec("ALTER TABLE codes ADD COLUMN copyable INTEGER DEFAULT 1"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, body := range []string{`{"code":""}`, `{"code":"XG-ABC"}`, `{"code":"` + strings.Repeat("G", 48) + `"}`} {
|
||||
if w := lookupRequest(s, body); w.Code != 400 {
|
||||
t.Fatalf("body %s: status=%d", body, w.Code)
|
||||
}
|
||||
}
|
||||
if w := lookupRequest(s, `{"code":"XG-`+strings.Repeat("B", 48)+`"}`); w.Code != 404 {
|
||||
t.Fatalf("unknown code: status=%d", w.Code)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLookupRequiresAdmin(t *testing.T) {
|
||||
s := resumeFixture(t, "review", "created")
|
||||
req := httptest.NewRequest("POST", "/api/admin/lookup", strings.NewReader(`{"code":"XG-`+strings.Repeat("A", 48)+`"}`))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
w := httptest.NewRecorder()
|
||||
s.admin(s.lookup)(w, req)
|
||||
if w.Code != 401 {
|
||||
t.Fatalf("unauthenticated lookup: status=%d", w.Code)
|
||||
}
|
||||
}
|
||||
@@ -37,6 +37,7 @@ type recoveryBatch struct {
|
||||
Created int64 `json:"created"`
|
||||
Updated int64 `json:"updated"`
|
||||
Last4 string `json:"last4"`
|
||||
Cards int `json:"cards"`
|
||||
Binding string `json:"binding,omitempty"`
|
||||
Paused bool `json:"paused"`
|
||||
Message string `json:"message"`
|
||||
@@ -207,7 +208,7 @@ func (s *server) recoveryPreview(w http.ResponseWriter, r *http.Request) {
|
||||
message(w, 409, "已有补单任务运行中,请先查看或停止。")
|
||||
return
|
||||
}
|
||||
last4, binding, err := checkout.CardSummary(s.vault)
|
||||
last4, cardCount, binding, err := checkout.CardSummary(s.vault)
|
||||
if err != nil {
|
||||
message(w, 503, "付款方式配置无法读取。")
|
||||
return
|
||||
@@ -243,7 +244,7 @@ func (s *server) recoveryPreview(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
q := &recoveryBatch{Mode: in.Mode, ID: token(16), State: "preview", Created: time.Now().Unix(), Last4: last4, Binding: binding, Paused: paused, Items: []recoveryItem{}}
|
||||
q := &recoveryBatch{Mode: in.Mode, ID: token(16), State: "preview", Created: time.Now().Unix(), Last4: last4, Cards: cardCount, Binding: binding, Paused: paused, Items: []recoveryItem{}}
|
||||
for _, id := range ids {
|
||||
item, e := s.recoveryCandidate(id)
|
||||
if e != nil {
|
||||
@@ -319,7 +320,7 @@ func (s *server) recoveryStart(w http.ResponseWriter, r *http.Request) {
|
||||
release()
|
||||
}
|
||||
}()
|
||||
_, binding, err := checkout.CardSummary(s.vault)
|
||||
_, _, binding, err := checkout.CardSummary(s.vault)
|
||||
if err != nil || binding != q.Binding {
|
||||
message(w, 409, "付款方式已变化,请重新预览。")
|
||||
return
|
||||
@@ -506,7 +507,7 @@ func (s *server) recoverOne(item recoveryItem, binding string) (state, detail st
|
||||
return s.recoverOneOptions(item, binding, "pay", false)
|
||||
}
|
||||
func (s *server) recoverOneOptions(item recoveryItem, binding, mode string, verified bool) (state, detail string, stop bool) {
|
||||
_, current, err := checkout.CardSummary(s.vault)
|
||||
_, _, current, err := checkout.CardSummary(s.vault)
|
||||
if err != nil || current != binding {
|
||||
return "blocked", "付款方式配置变化,已停止", true
|
||||
}
|
||||
|
||||
@@ -48,6 +48,7 @@ type server struct {
|
||||
port int
|
||||
lockPath string
|
||||
work chan struct{}
|
||||
checks chan struct{}
|
||||
jobs sync.WaitGroup
|
||||
ctx context.Context
|
||||
recoveryMu sync.Mutex
|
||||
@@ -108,7 +109,7 @@ func Run(ctx context.Context) error {
|
||||
if len(admin) < 32 {
|
||||
return errors.New("admin password must contain at least 32 characters")
|
||||
}
|
||||
s := &server{origin: origin, adminHash: sha256.Sum256(admin), payments: os.Getenv("XGIFT_PAYMENTS_ENABLED") == "true", lockPath: filepath.Join(dir, "checkout.lock"), work: make(chan struct{}, 1), ctx: ctx, limits: map[string]limit{}}
|
||||
s := &server{origin: origin, adminHash: sha256.Sum256(admin), payments: os.Getenv("XGIFT_PAYMENTS_ENABLED") == "true", lockPath: filepath.Join(dir, "checkout.lock"), work: make(chan struct{}, 1), checks: make(chan struct{}, 4), ctx: ctx, limits: map[string]limit{}}
|
||||
clear(admin)
|
||||
v, err := vault.Open(filepath.Join(dir, "vault.db"), os.Getenv("XGIFT_PASSWORD_FILE"), false)
|
||||
if err != nil {
|
||||
@@ -228,6 +229,7 @@ func Run(ctx context.Context) error {
|
||||
mux.HandleFunc("GET /admin", s.admin(s.asset("admin.html", "text/html; charset=utf-8")))
|
||||
mux.HandleFunc("GET /admin.js", s.admin(s.asset("admin.js", "application/javascript; charset=utf-8")))
|
||||
mux.HandleFunc("GET /api/admin/codes", s.admin(s.list))
|
||||
mux.HandleFunc("POST /api/admin/lookup", s.admin(s.lookup))
|
||||
mux.HandleFunc("GET /api/admin/stats", s.admin(s.stats))
|
||||
mux.HandleFunc("GET /api/admin/customer", s.admin(s.customerOrder))
|
||||
mux.HandleFunc("GET /api/admin/recovery", s.admin(s.recoveryStatus))
|
||||
@@ -481,8 +483,8 @@ func (s *server) status(w http.ResponseWriter, r *http.Request) {
|
||||
var eligibilityCheck = checkout.Eligibility
|
||||
|
||||
// check is a read-only eligibility probe: no code lookup, no checkout, no writes.
|
||||
// It stays available while payments are paused and shares the single X worker
|
||||
// slot with redemptions, but never queues behind one.
|
||||
// It stays available while payments are paused or running. Read-only checks
|
||||
// have their own bounded concurrency and never occupy the payment worker.
|
||||
func (s *server) check(w http.ResponseWriter, r *http.Request) {
|
||||
var q struct {
|
||||
Username string `json:"username"`
|
||||
@@ -496,10 +498,10 @@ func (s *server) check(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
select {
|
||||
case s.work <- struct{}{}:
|
||||
defer func() { <-s.work }()
|
||||
case s.checks <- struct{}{}:
|
||||
defer func() { <-s.checks }()
|
||||
default:
|
||||
message(w, 503, "正在处理其他请求,请稍后重试检测。")
|
||||
message(w, 503, "当前检测人数较多,请稍后重试检测。")
|
||||
return
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(r.Context(), 35*time.Second)
|
||||
|
||||
Reference in new issue
Block a user