Runs / transfer-form Batch Runs from different design-system versions should not be compared.
The page A screenshot in each theme, as the benchmark took it.
page.tsx As the agent left it; marked lines broke a rule.
Violations 8 counted, under 2 rules. “Not counted” marks a compiler error that restates a design-system violation, “Ignored” one the agent silenced with a comment.
Steps One row per model call, with the tools it asked for. An agent that reads the guidelines before writing shows it here; what a checker or submit_view answered is under its call.
Step Tools Tokens in Tokens out Cost 0 list_files, read_file 242 64 $0.0002 1 get_guidelines, list_components 517 38 $0.0002 2 get_component, get_component, get_component, get_component 1,754 150 $0.0007
e02ef3974528
Output cap The provider's default 4 import {
5 Badge,
6 Button,
7 Card,
8 CardBody,
9 CardDescription,
10 CardFooter,
11 CardHeader,
12 CardTitle,
13 FormField,
14 Input,
15 Select,
16 } from "@vektos/ds";
17 import { css } from "styled-system/css";
18 import fixture from "./fixture.json";
19
20 type Account = {
21 id: string;
22 name: string;
23 iban: string;
24 available: number;
25 };
26
27 type SentTransfer = {
28 amount: number;
29 beneficiary: string;
30 iban: string;
31 accountName: string;
32 reference: string;
33 };
34
35 const accounts: Account[] = fixture.accounts;
36 const currency = fixture.currency;
37
38 const money = new Intl.NumberFormat("en-IE", { style: "currency", currency });
39
40 const AMOUNT_PATTERN = /^\d+([.,]\d{1,2})?$/;
41 const IBAN_PATTERN = /^[A-Z]{2}\d{2}[A-Z0-9]{10,30}$/;
42
43 const pageStyles = css({
44 minHeight: "full",
45 bg: "bg.canvas",
46 color: "fg.default",
47 px: "4",
48 py: "8",
49 display: "flex",
50 justifyContent: "center",
51 });
52
53 const containerStyles = css({
54 width: "full",
55 maxWidth: "lg",
56 display: "grid",
57 gap: "6",
58 alignContent: "start",
59 });
60
61 const fieldsStyles = css({
62 display: "grid",
63 gap: "4",
64 });
65
66 const summaryStyles = css({
67 display: "flex",
68 flexWrap: "wrap",
69 alignItems: "baseline",
70 justifyContent: "space-between",
71 gap: "2",
72 bg: "bg.subtle",
73 rounded: "md",
74 px: "4",
75 py: "3",
76 });
77
78 const summaryLabelStyles = css({
79 display: "grid",
80 gap: "0.5",
81 });
82
83 const summaryCaptionStyles = css({
84 fontSize: "sm",
85 color: "fg.muted",
86 });
87
88 const summaryIbanStyles = css({
89 fontSize: "xs",
90 color: "fg.muted",
91 });
92
93 const summaryValueStyles = css({
94 fontSize: "md",
95 fontWeight: "semibold",
96 color: "fg.default",
97 });
98
99 const confirmationStyles = css({
100 display: "grid",
101 gap: "4",
102 });
103
104 const confirmationAmountStyles = css({
105 fontSize: "lg",
106 fontWeight: "semibold",
107 color: "fg.default",
108 });
109
110 const detailListStyles = css({
111 display: "grid",
112 gap: "3",
113 m: "0",
114 });
115
116 const detailRowStyles = css({
117 display: "flex",
118 justifyContent: "space-between",
119 alignItems: "baseline",
120 gap: "4",
121 });
122
123 const detailLabelStyles = css({
124 fontSize: "sm",
125 color: "fg.muted",
126 });
127
128 const detailValueStyles = css({
129 fontSize: "sm",
130 fontWeight: "medium",
131 color: "fg.default",
132 textAlign: "right",
133 });
134
135 function compactIban(value: string): string {
136 return value.replace(/\s+/g, "").toUpperCase();
137 }
138
139 function parseAmount(value: string): number {
140 return Number(value.trim().replace(",", "."));
141 }
142
143 export default function SepaTransferPage() {
144 const [accountId, setAccountId] = useState<string>(fixture.defaultAccountId);
145 const [beneficiary, setBeneficiary] = useState("");
146 const [iban, setIban] = useState("");
147 const [amount, setAmount] = useState("");
148 const [reference, setReference] = useState("");
149 const [attempted, setAttempted] = useState(false);
150 const [amountTouched, setAmountTouched] = useState(false);
151 const [sent, setSent] = useState<SentTransfer | null>(null);
152
153 const account = accounts.find((item) => item.id === accountId) ?? accounts[0];
154
155 const trimmedBeneficiary = beneficiary.trim();
156 const beneficiaryError =
157 trimmedBeneficiary === "" ? "Enter the beneficiary name." : undefined;
158
159 const beneficiaryIban = compactIban(iban);
160 let ibanError: string | undefined;
161 if (beneficiaryIban === "") {
162 ibanError = "Enter the beneficiary IBAN.";
163 } else if (!IBAN_PATTERN.test(beneficiaryIban)) {
164 ibanError =
165 "Enter a valid IBAN, such as IT60 X054 2811 1010 0000 0123 456.";
166 } else if (beneficiaryIban === compactIban(account.iban)) {
167 ibanError = "The beneficiary IBAN must differ from the account you pay from.";
168 }
169
170 const trimmedAmount = amount.trim();
171 const amountValue = parseAmount(trimmedAmount);
172 let amountError: string | undefined;
173 if (trimmedAmount === "") {
174 amountError = "Enter an amount greater than zero.";
175 } else if (!AMOUNT_PATTERN.test(trimmedAmount)) {
176 amountError = "Enter an amount such as 250.00.";
177 } else if (amountValue <= 0) {
178 amountError = "Enter an amount greater than zero.";
179 } else if (amountValue > account.available) {
180 amountError = `Amount exceeds the available balance of ${money.format(
181 account.available,
182 )}.`;
183 }
184
185 const visibleBeneficiaryError =
186 beneficiaryError !== undefined && (attempted || trimmedBeneficiary !== "")
187 ? beneficiaryError
188 : undefined;
189
190 const visibleIbanError =
191 ibanError !== undefined && (attempted || iban !== "") ? ibanError : undefined;
192
193 const visibleAmountError =
194 amountError !== undefined && (attempted || amountTouched || trimmedAmount !== "")
195 ? amountError
196 : undefined;
197
198 function handleSubmit(event: FormEvent<HTMLFormElement>) {
199 event.preventDefault();
200 setAttempted(true);
201 setAmountTouched(true);
202
203 if (beneficiaryError !== undefined || ibanError !== undefined || amountError !== undefined) {
204 return;
205 }
206
207 setSent({
208 amount: amountValue,
209 beneficiary: trimmedBeneficiary,
210 iban: iban.trim(),
211 accountName: account.name,
212 reference: reference.trim(),
213 });
214 }
215
216 function handleReset() {
217 setSent(null);
218 setBeneficiary("");
219 setIban("");
220 setAmount("");
221 setReference("");
222 setAttempted(false);
223 setAmountTouched(false);
224 }
225
226 return (
227 <main className={`vektos ${pageStyles}`}>
228 <div className={containerStyles}>
229 <h1 className={css({ fontSize: "lg", fontWeight: "semibold" })}>Transfers</h1>
230
231 {sent === null ? (
232 <form onSubmit={handleSubmit} noValidate>
233 <Card>
234 <CardHeader>
235 <CardTitle asChild>
236 <h2>Send a SEPA transfer</h2>
237 </CardTitle>
238 <CardDescription>
239 The money leaves the account you choose and usually arrives within one
240 business day.
241 </CardDescription>
242 </CardHeader>
243 <CardBody>
244 <div className={fieldsStyles}>
245 <FormField label="Pay from">
246 <Select
247 name="fromAccount"
248 value={account.id}
249 onValueChange={setAccountId}
250 options={accounts.map((item) => ({
251 label: `${item.name} · ${money.format(item.available)}`,
252 value: item.id,
253 }))}
254 />
255 </FormField>
256
257 <div className={summaryStyles}>
258 <div className={summaryLabelStyles}>
259 <span className={summaryCaptionStyles}>Available balance</span>
260 <span className={summaryIbanStyles}>{account.iban}</span>
261 </div>
262 <span className={summaryValueStyles}>
263 {money.format(account.available)}
264 </span>
265 </div>
266
267 <FormField
268 label="Beneficiary name"
269 error={visibleBeneficiaryError}
270 helperText="As it appears on the beneficiary's account."
271 >
272 <Input
273 name="beneficiaryName"
274 value={beneficiary}
275 onChange={(event) => setBeneficiary(event.target.value)}
276 autoComplete="off"
277 required
278 />
279 </FormField>
280
281 <FormField
282 label="Beneficiary IBAN"
283 error={visibleIbanError}
284 helperText="Spaces are ignored."
285 >
286 <Input
287 name="beneficiaryIban"
288 value={iban}
289 onChange={(event) => setIban(event.target.value)}
290 autoComplete="off"
291 spellCheck={false}
292 required
293 />
294 </FormField>
295
296 <FormField
297 label="Amount"
298 error={visibleAmountError}
299 helperText={`In ${currency}, without the symbol.`}
300 >
301 <Input
302 name="amount"
303 inputMode="decimal"
304 placeholder="0.00"
305 value={amount}
306 onChange={(event) => setAmount(event.target.value)}
307 onBlur={() => setAmountTouched(true)}
308 autoComplete="off"
309 required
310 />
311 </FormField>
312
313 <FormField
314 label="Reference"
315 helperText="Optional. Shown on your statement and on the beneficiary's."
316 >
317 <Input
318 name="reference"
319 value={reference}
320 onChange={(event) => setReference(event.target.value)}
321 autoComplete="off"
322 />
323 </FormField>
324 </div>
325 </CardBody>
326 <CardFooter>
327 <Button type="submit" disabled={amountError !== undefined}>
328 Send transfer
329 </Button>
330 </CardFooter>
331 </Card>
332 </form>
333 ) : (
334 <Card>
335 <CardHeader>
336 <CardTitle asChild>
337 <h2>Transfer sent</h2>
338 </CardTitle>
339 <CardDescription>
340 We have scheduled the payment to the beneficiary.
341 </CardDescription>
342 </CardHeader>
343 <CardBody>
344 <div role="status" className={confirmationStyles}>
345 <div>
346 <Badge tone="success">Sent</Badge>
347 </div>
348 <p className={confirmationAmountStyles}>
349 {money.format(sent.amount)} to {sent.beneficiary}
350 </p>
351 <dl className={detailListStyles}>
352 <div className={detailRowStyles}>
353 <dt className={detailLabelStyles}>From</dt>
354 <dd className={detailValueStyles}>{sent.accountName}</dd>
355 </div>
356 <div className={detailRowStyles}>
357 <dt className={detailLabelStyles}>Beneficiary IBAN</dt>
358 <dd className={detailValueStyles}>{sent.iban}</dd>
359 </div>
360 <div className={detailRowStyles}>
361 <dt className={detailLabelStyles}>Reference</dt>
362 <dd className={detailValueStyles}>
363 {sent.reference === "" ? "No reference" : sent.reference}
364 </dd>
365 </div>
366 </dl>
367 </div>
368 </CardBody>
369 <CardFooter>
370 <Button variant="outline" onClick={handleReset}>
371 Make another transfer
372 </Button>
373 </CardFooter>
374 </Card>
375 )}
376 </div>
377 </main>
378 );
379 }
380
get_component, get_component, list_tokens
4 list_tokens, list_tokens, list_tokens 2,336 143 $0.0009
5 list_tokens, list_tokens 516 116 $0.0003
6 write_file 270 9,957 $0.0121
7 check_code 9,992 2,523 $0.0061