ロイヤリティ要約カードLoyaltySummaryCardExperimental
ポイント残高、会員ランク、次ランクまでの進捗、失効通知、主操作をまとめる会員カードです。
プレビュー
ハッピーズドラッグ メンバーズ
ゴールド会員
ポイント残高
3,480P
当年購入額
¥86,200
クーポン
3枚
プラチナ会員まで あと ¥13,800¥86,200 / ¥100,000
200 P が 2026/06/30 に失効予定です
状態とバリエーション
ブランド面
既定の brand は塗りつぶしの会員カードです。
ハッピーズドラッグ メンバーズ
ゴールド会員
ポイント残高
3,480P
当年購入額
¥86,200
クーポン
3枚
プラチナ会員まで あと ¥13,800¥86,200 / ¥100,000
200 P が 2026/06/30 に失効予定です
通常カード
周囲が強い画面では tone="default" を使います。
ハッピーズドラッグ メンバーズ
ゴールド会員
ポイント残高
3,480P
当年購入額
¥86,200
クーポン
3枚
プラチナ会員まで あと ¥13,800¥86,200 / ¥100,000
200 P が 2026/06/30 に失効予定です
警告なし
失効予定がない場合は alert を省略します。
ハッピーズドラッグ メンバーズ
ゴールド会員
ポイント残高
3,480P
当年購入額
¥86,200
クーポン
3枚
プラチナ会員まで あと ¥13,800¥86,200 / ¥100,000
プロパティ
表は横にスクロールできます
| プロパティ | 型 | 初期値 | 説明 |
|---|---|---|---|
| balance | ReactNode | - | 大きく表示する残高です。 |
| balanceLabel | ReactNode | - | 残高の上の小ラベルです。 |
| unit | ReactNode | - | P、マイル、円などの単位です。 |
| meta | ReactNode | - | プログラム名、会員名、番号などです。 |
| tier | ReactNode | - | 会員ランク Badge などです。 |
| secondary | { label, value }[] | - | 残高下に並べる副次値です。 |
| progress | { value, max, label?, caption? } | - | 次ランクまでの進捗です。高いほど良い値として扱います。 |
| alert | ReactNode | - | 失効予定などの注意行です。 |
| action | ReactNode | - | 会員バーコード表示などの主操作です。 |
| tone | "brand" | "default" | "brand" | brand は塗りつぶしヒーロー、default は通常カードです。 |
使い方
import * as React from "react";
import {
Badge,
Button,
Dialog,
DialogContent,
DialogDescription,
DialogFooter,
DialogHeader,
DialogTitle,
LoyaltySummaryCard,
} from "@gunjo/ui";
export function MemberSummary() {
const rootRef = React.useRef<HTMLDivElement | null>(null);
const [portalContainer, setPortalContainer] = React.useState<HTMLElement | null>(null);
const [barcodeOpen, setBarcodeOpen] = React.useState(false);
React.useEffect(() => {
setPortalContainer(rootRef.current?.closest<HTMLElement>("[data-doc-component-preview-surface]") ?? rootRef.current);
}, []);
return (
<div ref={rootRef} className="flex w-full max-w-md flex-col gap-4">
<LoyaltySummaryCard
tone="brand"
meta="ハッピーズドラッグ メンバーズ"
tier={<Badge variant="outline" className="border-primary-strong-foreground/45 text-primary-strong-foreground">ゴールド会員</Badge>}
balanceLabel="ポイント残高"
balance="3,480"
unit="P"
secondary={[{ label: "当年購入額", value: "¥86,200" }, { label: "クーポン", value: "3枚" }]}
progress={{ value: 86200, max: 100000, label: "プラチナ会員まで あと ¥13,800", caption: "¥86,200 / ¥100,000" }}
alert="200 P が 2026/06/30 に失効予定です"
action={<Button size="lg" variant="secondary" className="w-full" onClick={() => setBarcodeOpen(true)}>会員バーコードを表示</Button>}
/>
<Dialog open={barcodeOpen} onOpenChange={setBarcodeOpen} modal={false}>
<DialogContent portalContainer={portalContainer} overlayClassName="rounded-md" closeLabel="閉じる" className="max-w-sm">
<DialogHeader>
<DialogTitle>会員バーコード</DialogTitle>
<DialogDescription>レジでこのコードを提示します。</DialogDescription>
</DialogHeader>
<div className="grid gap-3 rounded-lg border bg-card p-4 text-center">
<p className="text-sm font-medium text-foreground">ハッピーズドラッグ メンバーズ</p>
<div className="mx-auto h-24 w-full max-w-[260px] rounded bg-[repeating-linear-gradient(90deg,hsl(var(--foreground))_0_2px,transparent_2px_4px,hsl(var(--foreground))_4px_7px,transparent_7px_10px,hsl(var(--foreground))_10px_11px,transparent_11px_14px)]" />
<p className="font-mono text-sm tracking-widest text-foreground">3480 0626 2026</p>
</div>
<DialogFooter>
<Button type="button" variant="outline" onClick={() => setBarcodeOpen(false)}>閉じる</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</div>
);
}設計の判断
- 残高の桁を最優先に置いた。資料は「情報の優先順位を決める」を判断の核に挙げています。この部品は残高を最上段の大きな等幅数字として置き、ランク・二次的な値・次のランクまでの進捗・失効の注意・行動ボタン、の順に並べます。この順は差し替えられません。
- 進捗は「多いほど良い」側だけを持つ。満杯に近づくと赤くなる
Meterとは違い、ここでは色が変わりません。ポイントが貯まることは警告ではないからです。「あと 13,800円」のような残りの表示は、progress.labelとして呼ぶ側が書きます。 - 華やかな面は
brandの1つだけ用意した。tone="brand"は塗りつぶしの面で、ブランド色のクラスをその場で書かずに見栄えを出すための逃げ道です。落ち着かせたいときはtone="default"で普通のカードに戻ります。任意の色を渡す口は開けていません。
一般のカードの設計は UIXHERO の「カード」にあります。 UIXHERO: カード(Card)