small details
This commit is contained in:
parent
61ae2807de
commit
86c92a7c65
11 changed files with 328 additions and 184 deletions
|
|
@ -224,168 +224,212 @@ export default function AdminPricingPage() {
|
||||||
isLoading={isLoading}
|
isLoading={isLoading}
|
||||||
isAuthorized={isAuthorized}
|
isAuthorized={isAuthorized}
|
||||||
error={displayError}
|
error={displayError}
|
||||||
|
contentStyle={{
|
||||||
|
flex: 1,
|
||||||
|
display: "flex",
|
||||||
|
alignItems: "flex-start",
|
||||||
|
justifyContent: "center",
|
||||||
|
padding: "2rem",
|
||||||
|
overflowY: "auto",
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<div style={cardStyles.card}>
|
<div style={{ ...cardStyles.card, width: "100%", maxWidth: "1400px" }}>
|
||||||
<h1 style={cardStyles.title}>{t("pricing.title")}</h1>
|
<h1 style={cardStyles.cardTitle}>{t("pricing.title")}</h1>
|
||||||
<p style={cardStyles.subtitle}>{t("pricing.subtitle")}</p>
|
<p style={cardStyles.cardSubtitle}>{t("pricing.subtitle")}</p>
|
||||||
|
|
||||||
{success && <div style={bannerStyles.success}>{t("pricing.success")}</div>}
|
{success && <div style={bannerStyles.success}>{t("pricing.success")}</div>}
|
||||||
|
|
||||||
<form
|
<form
|
||||||
onSubmit={(e) => {
|
onSubmit={(e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
handleSave();
|
setIsConfirming(true);
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{/* Premium Settings - Full Width */}
|
||||||
<div style={formStyles.section}>
|
<div style={formStyles.section}>
|
||||||
<h2 style={formStyles.sectionTitle}>{t("pricing.premiumSettings")}</h2>
|
<h2 style={formStyles.sectionTitle}>{t("pricing.premiumSettings")}</h2>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "grid",
|
||||||
|
gridTemplateColumns: "repeat(4, minmax(200px, 1fr))",
|
||||||
|
gap: "1.5rem",
|
||||||
|
alignItems: "start",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={formStyles.field}>
|
||||||
|
<label style={formStyles.label}>{t("pricing.premiumBuy")} (%)</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
value={formData.premium_buy}
|
||||||
|
onChange={(e) => handleFieldChange("premium_buy", e.target.value)}
|
||||||
|
min={-100}
|
||||||
|
max={100}
|
||||||
|
style={{
|
||||||
|
...formStyles.input,
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: "180px",
|
||||||
|
...(errors.premium_buy ? formStyles.inputError : {}),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{errors.premium_buy && <div style={formStyles.error}>{errors.premium_buy}</div>}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style={formStyles.field}>
|
<div style={formStyles.field}>
|
||||||
<label style={formStyles.label}>{t("pricing.premiumBuy")} (%)</label>
|
<label style={formStyles.label}>{t("pricing.premiumSell")} (%)</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
value={formData.premium_buy}
|
value={formData.premium_sell}
|
||||||
onChange={(e) => handleFieldChange("premium_buy", e.target.value)}
|
onChange={(e) => handleFieldChange("premium_sell", e.target.value)}
|
||||||
min={-100}
|
min={-100}
|
||||||
max={100}
|
max={100}
|
||||||
style={{
|
style={{
|
||||||
...formStyles.input,
|
...formStyles.input,
|
||||||
...(errors.premium_buy ? formStyles.inputError : {}),
|
width: "100%",
|
||||||
}}
|
maxWidth: "180px",
|
||||||
/>
|
...(errors.premium_sell ? formStyles.inputError : {}),
|
||||||
{errors.premium_buy && <div style={formStyles.error}>{errors.premium_buy}</div>}
|
}}
|
||||||
</div>
|
/>
|
||||||
|
{errors.premium_sell && <div style={formStyles.error}>{errors.premium_sell}</div>}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style={formStyles.field}>
|
<div style={formStyles.field}>
|
||||||
<label style={formStyles.label}>{t("pricing.premiumSell")} (%)</label>
|
<label style={formStyles.label}>{t("pricing.smallTradeThreshold")} (EUR)</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
value={formData.premium_sell}
|
value={formData.small_trade_threshold_eur / 100}
|
||||||
onChange={(e) => handleFieldChange("premium_sell", e.target.value)}
|
onChange={(e) =>
|
||||||
min={-100}
|
handleFieldChange(
|
||||||
max={100}
|
"small_trade_threshold_eur",
|
||||||
style={{
|
(parseFloat(e.target.value) * 100).toString()
|
||||||
...formStyles.input,
|
)
|
||||||
...(errors.premium_sell ? formStyles.inputError : {}),
|
}
|
||||||
}}
|
min={1}
|
||||||
/>
|
style={{
|
||||||
{errors.premium_sell && <div style={formStyles.error}>{errors.premium_sell}</div>}
|
...formStyles.input,
|
||||||
</div>
|
width: "100%",
|
||||||
|
maxWidth: "180px",
|
||||||
|
...(errors.small_trade_threshold_eur ? formStyles.inputError : {}),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{errors.small_trade_threshold_eur && (
|
||||||
|
<div style={formStyles.error}>{errors.small_trade_threshold_eur}</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style={formStyles.field}>
|
<div style={formStyles.field}>
|
||||||
<label style={formStyles.label}>{t("pricing.smallTradeThreshold")} (EUR)</label>
|
<label style={formStyles.label}>{t("pricing.smallTradeExtraPremium")} (%)</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
value={formData.small_trade_threshold_eur / 100}
|
value={formData.small_trade_extra_premium}
|
||||||
onChange={(e) =>
|
onChange={(e) => handleFieldChange("small_trade_extra_premium", e.target.value)}
|
||||||
handleFieldChange(
|
min={-100}
|
||||||
"small_trade_threshold_eur",
|
max={100}
|
||||||
(parseFloat(e.target.value) * 100).toString()
|
style={{
|
||||||
)
|
...formStyles.input,
|
||||||
}
|
width: "100%",
|
||||||
min={1}
|
maxWidth: "180px",
|
||||||
style={{
|
...(errors.small_trade_extra_premium ? formStyles.inputError : {}),
|
||||||
...formStyles.input,
|
}}
|
||||||
...(errors.small_trade_threshold_eur ? formStyles.inputError : {}),
|
/>
|
||||||
}}
|
{errors.small_trade_extra_premium && (
|
||||||
/>
|
<div style={formStyles.error}>{errors.small_trade_extra_premium}</div>
|
||||||
{errors.small_trade_threshold_eur && (
|
)}
|
||||||
<div style={formStyles.error}>{errors.small_trade_threshold_eur}</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style={formStyles.field}>
|
|
||||||
<label style={formStyles.label}>{t("pricing.smallTradeExtraPremium")} (%)</label>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
value={formData.small_trade_extra_premium}
|
|
||||||
onChange={(e) => handleFieldChange("small_trade_extra_premium", e.target.value)}
|
|
||||||
min={-100}
|
|
||||||
max={100}
|
|
||||||
style={{
|
|
||||||
...formStyles.input,
|
|
||||||
...(errors.small_trade_extra_premium ? formStyles.inputError : {}),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{errors.small_trade_extra_premium && (
|
|
||||||
<div style={formStyles.error}>{errors.small_trade_extra_premium}</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={formStyles.section}>
|
{/* Trade Limits - Side by Side */}
|
||||||
<h2 style={formStyles.sectionTitle}>{t("pricing.tradeLimitsBuy")}</h2>
|
<div
|
||||||
|
style={{
|
||||||
|
display: "grid",
|
||||||
|
gridTemplateColumns: "repeat(2, minmax(300px, 1fr))",
|
||||||
|
gap: "2rem",
|
||||||
|
marginBottom: "2rem",
|
||||||
|
alignItems: "start",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ ...formStyles.section, marginBottom: 0 }}>
|
||||||
|
<h2 style={formStyles.sectionTitle}>{t("pricing.tradeLimitsBuy")}</h2>
|
||||||
|
|
||||||
<div style={formStyles.field}>
|
<div style={formStyles.field}>
|
||||||
<label style={formStyles.label}>{t("pricing.minAmount")} (EUR)</label>
|
<label style={formStyles.label}>{t("pricing.minAmount")} (EUR)</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
value={formData.eur_min_buy / 100}
|
value={formData.eur_min_buy / 100}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleFieldChange("eur_min_buy", (parseFloat(e.target.value) * 100).toString())
|
handleFieldChange("eur_min_buy", (parseFloat(e.target.value) * 100).toString())
|
||||||
}
|
}
|
||||||
min={1}
|
min={1}
|
||||||
style={{
|
style={{
|
||||||
...formStyles.input,
|
...formStyles.input,
|
||||||
...(errors.eur_min_buy ? formStyles.inputError : {}),
|
width: "100%",
|
||||||
}}
|
maxWidth: "180px",
|
||||||
/>
|
...(errors.eur_min_buy ? formStyles.inputError : {}),
|
||||||
{errors.eur_min_buy && <div style={formStyles.error}>{errors.eur_min_buy}</div>}
|
}}
|
||||||
|
/>
|
||||||
|
{errors.eur_min_buy && <div style={formStyles.error}>{errors.eur_min_buy}</div>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={formStyles.field}>
|
||||||
|
<label style={formStyles.label}>{t("pricing.maxAmount")} (EUR)</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
value={formData.eur_max_buy / 100}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleFieldChange("eur_max_buy", (parseFloat(e.target.value) * 100).toString())
|
||||||
|
}
|
||||||
|
min={1}
|
||||||
|
style={{
|
||||||
|
...formStyles.input,
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: "180px",
|
||||||
|
...(errors.eur_max_buy ? formStyles.inputError : {}),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{errors.eur_max_buy && <div style={formStyles.error}>{errors.eur_max_buy}</div>}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={formStyles.field}>
|
<div style={{ ...formStyles.section, marginBottom: 0 }}>
|
||||||
<label style={formStyles.label}>{t("pricing.maxAmount")} (EUR)</label>
|
<h2 style={formStyles.sectionTitle}>{t("pricing.tradeLimitsSell")}</h2>
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
value={formData.eur_max_buy / 100}
|
|
||||||
onChange={(e) =>
|
|
||||||
handleFieldChange("eur_max_buy", (parseFloat(e.target.value) * 100).toString())
|
|
||||||
}
|
|
||||||
min={1}
|
|
||||||
style={{
|
|
||||||
...formStyles.input,
|
|
||||||
...(errors.eur_max_buy ? formStyles.inputError : {}),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{errors.eur_max_buy && <div style={formStyles.error}>{errors.eur_max_buy}</div>}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div style={formStyles.section}>
|
<div style={formStyles.field}>
|
||||||
<h2 style={formStyles.sectionTitle}>{t("pricing.tradeLimitsSell")}</h2>
|
<label style={formStyles.label}>{t("pricing.minAmount")} (EUR)</label>
|
||||||
|
<input
|
||||||
|
type="number"
|
||||||
|
value={formData.eur_min_sell / 100}
|
||||||
|
onChange={(e) =>
|
||||||
|
handleFieldChange("eur_min_sell", (parseFloat(e.target.value) * 100).toString())
|
||||||
|
}
|
||||||
|
min={1}
|
||||||
|
style={{
|
||||||
|
...formStyles.input,
|
||||||
|
width: "100%",
|
||||||
|
maxWidth: "180px",
|
||||||
|
...(errors.eur_min_sell ? formStyles.inputError : {}),
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
{errors.eur_min_sell && <div style={formStyles.error}>{errors.eur_min_sell}</div>}
|
||||||
|
</div>
|
||||||
|
|
||||||
<div style={formStyles.field}>
|
<div style={formStyles.field}>
|
||||||
<label style={formStyles.label}>{t("pricing.minAmount")} (EUR)</label>
|
<label style={formStyles.label}>{t("pricing.maxAmount")} (EUR)</label>
|
||||||
<input
|
<input
|
||||||
type="number"
|
type="number"
|
||||||
value={formData.eur_min_sell / 100}
|
value={formData.eur_max_sell / 100}
|
||||||
onChange={(e) =>
|
onChange={(e) =>
|
||||||
handleFieldChange("eur_min_sell", (parseFloat(e.target.value) * 100).toString())
|
handleFieldChange("eur_max_sell", (parseFloat(e.target.value) * 100).toString())
|
||||||
}
|
}
|
||||||
min={1}
|
min={1}
|
||||||
style={{
|
style={{
|
||||||
...formStyles.input,
|
...formStyles.input,
|
||||||
...(errors.eur_min_sell ? formStyles.inputError : {}),
|
width: "100%",
|
||||||
}}
|
maxWidth: "180px",
|
||||||
/>
|
...(errors.eur_max_sell ? formStyles.inputError : {}),
|
||||||
{errors.eur_min_sell && <div style={formStyles.error}>{errors.eur_min_sell}</div>}
|
}}
|
||||||
</div>
|
/>
|
||||||
|
{errors.eur_max_sell && <div style={formStyles.error}>{errors.eur_max_sell}</div>}
|
||||||
<div style={formStyles.field}>
|
</div>
|
||||||
<label style={formStyles.label}>{t("pricing.maxAmount")} (EUR)</label>
|
|
||||||
<input
|
|
||||||
type="number"
|
|
||||||
value={formData.eur_max_sell / 100}
|
|
||||||
onChange={(e) =>
|
|
||||||
handleFieldChange("eur_max_sell", (parseFloat(e.target.value) * 100).toString())
|
|
||||||
}
|
|
||||||
min={1}
|
|
||||||
style={{
|
|
||||||
...formStyles.input,
|
|
||||||
...(errors.eur_max_sell ? formStyles.inputError : {}),
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{errors.eur_max_sell && <div style={formStyles.error}>{errors.eur_max_sell}</div>}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -345,36 +345,43 @@ export function ExchangeDetailsStep({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Trade Summary */}
|
{/* Trade Summary */}
|
||||||
<div style={styles.tradeSummary}>
|
<div style={styles.tradeSummary} data-testid="trade-summary">
|
||||||
{direction === "buy" ? (
|
{direction === "buy" ? (
|
||||||
<p style={styles.summaryText}>
|
<p style={styles.summaryText}>
|
||||||
{t("detailsStep.summaryBuy", { sats: "", eur: "" }).split("{sats}")[0].trim()}{" "}
|
{t("detailsStep.summaryBuy", {
|
||||||
<strong style={styles.satsValue}>
|
eur: formatEur(eurAmount),
|
||||||
<SatsDisplay sats={satsAmount} />
|
sats: "",
|
||||||
</strong>
|
})
|
||||||
{", "}
|
.replace("{eur}", formatEur(eurAmount))
|
||||||
{t("detailsStep.summaryBuy", { sats: "", eur: "" })
|
.split("{sats}")
|
||||||
.split("{sats}")[1]
|
.map((part, i) => (
|
||||||
?.split("{eur}")[0]
|
<span key={i}>
|
||||||
?.trim()}{" "}
|
{part}
|
||||||
<strong>{formatEur(eurAmount)}</strong>
|
{i === 0 && (
|
||||||
|
<strong style={styles.satsValue}>
|
||||||
|
<SatsDisplay sats={satsAmount} />
|
||||||
|
</strong>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
))}
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<p style={styles.summaryText}>
|
<p style={styles.summaryText}>
|
||||||
{t("detailsStep.summarySell", { sats: "", eur: "" })
|
{t("detailsStep.summarySell", {
|
||||||
.split("{sats}")[0]
|
sats: "",
|
||||||
?.split("{eur}")[0]
|
eur: formatEur(eurAmount),
|
||||||
?.trim()}{" "}
|
})
|
||||||
<strong>{formatEur(eurAmount)}</strong>
|
.split("{sats}")
|
||||||
{", "}
|
.map((part, i) => (
|
||||||
{t("detailsStep.summarySell", { sats: "", eur: "" })
|
<span key={i}>
|
||||||
.split("{sats}")[0]
|
{i === 0 && (
|
||||||
?.split("{eur}")[1]
|
<strong style={styles.satsValue}>
|
||||||
?.trim()}{" "}
|
<SatsDisplay sats={satsAmount} />
|
||||||
<strong style={styles.satsValue}>
|
</strong>
|
||||||
<SatsDisplay sats={satsAmount} />
|
)}
|
||||||
</strong>
|
{part.replace("{eur}", formatEur(eurAmount))}
|
||||||
{t("detailsStep.summarySell", { sats: "", eur: "" }).split("{sats}")[1]?.trim()}
|
</span>
|
||||||
|
))}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -439,6 +439,30 @@ export const formStyles: StyleRecord = {
|
||||||
fontSize: "0.75rem",
|
fontSize: "0.75rem",
|
||||||
color: "#fca5a5",
|
color: "#fca5a5",
|
||||||
},
|
},
|
||||||
|
error: {
|
||||||
|
fontFamily: tokens.fontSans,
|
||||||
|
fontSize: "0.75rem",
|
||||||
|
color: "#fca5a5",
|
||||||
|
marginTop: "0.25rem",
|
||||||
|
},
|
||||||
|
section: {
|
||||||
|
marginBottom: "2rem",
|
||||||
|
},
|
||||||
|
sectionTitle: {
|
||||||
|
fontFamily: tokens.fontSans,
|
||||||
|
fontSize: "1rem",
|
||||||
|
fontWeight: 600,
|
||||||
|
color: tokens.textSecondary,
|
||||||
|
marginBottom: "1.25rem",
|
||||||
|
marginTop: 0,
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "flex-end",
|
||||||
|
marginTop: "2rem",
|
||||||
|
paddingTop: "1.5rem",
|
||||||
|
borderTop: `1px solid ${tokens.surfaceBorder}`,
|
||||||
|
},
|
||||||
charCount: {
|
charCount: {
|
||||||
fontFamily: tokens.fontSans,
|
fontFamily: tokens.fontSans,
|
||||||
fontSize: "0.75rem",
|
fontSize: "0.75rem",
|
||||||
|
|
@ -511,6 +535,26 @@ export const buttonStyles: StyleRecord = {
|
||||||
cursor: "not-allowed",
|
cursor: "not-allowed",
|
||||||
boxShadow: "none",
|
boxShadow: "none",
|
||||||
},
|
},
|
||||||
|
/** Primary button alias (for backwards compatibility) */
|
||||||
|
primary: {
|
||||||
|
fontFamily: tokens.fontSans,
|
||||||
|
padding: "1rem",
|
||||||
|
fontSize: "1rem",
|
||||||
|
fontWeight: 600,
|
||||||
|
background: tokens.primaryGradient,
|
||||||
|
color: tokens.white,
|
||||||
|
border: "none",
|
||||||
|
borderRadius: tokens.radiusLg,
|
||||||
|
cursor: "pointer",
|
||||||
|
transition: "transform 0.2s, box-shadow 0.2s",
|
||||||
|
boxShadow: tokens.buttonShadow,
|
||||||
|
},
|
||||||
|
/** Disabled button alias (for backwards compatibility) */
|
||||||
|
disabled: {
|
||||||
|
opacity: 0.5,
|
||||||
|
cursor: "not-allowed",
|
||||||
|
boxShadow: "none",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
@ -575,6 +619,17 @@ export const bannerStyles: StyleRecord = {
|
||||||
color: "#4ade80",
|
color: "#4ade80",
|
||||||
marginBottom: "1rem",
|
marginBottom: "1rem",
|
||||||
},
|
},
|
||||||
|
/** Success banner alias (for backwards compatibility) */
|
||||||
|
success: {
|
||||||
|
fontFamily: tokens.fontSans,
|
||||||
|
fontSize: "0.875rem",
|
||||||
|
padding: "1rem",
|
||||||
|
background: "rgba(34, 197, 94, 0.15)",
|
||||||
|
border: `1px solid ${tokens.successBorder}`,
|
||||||
|
borderRadius: tokens.radiusMd,
|
||||||
|
color: "#4ade80",
|
||||||
|
marginBottom: "1rem",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// =============================================================================
|
// =============================================================================
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,44 @@ test.describe("Exchange Page - Regular User Access", () => {
|
||||||
timeout: 10000,
|
timeout: 10000,
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("summary card displays correct text for buy and sell directions", async ({ page }) => {
|
||||||
|
await page.goto("/exchange");
|
||||||
|
await expect(page.getByRole("heading", { name: "Exchange Bitcoin" })).toBeVisible();
|
||||||
|
|
||||||
|
// Wait for price data to load
|
||||||
|
await expect(page.getByText("Market:")).toBeVisible({ timeout: 5000 });
|
||||||
|
|
||||||
|
// Test BUY direction summary
|
||||||
|
const buyButton = page.getByRole("button", { name: "Buy BTC" });
|
||||||
|
await buyButton.click();
|
||||||
|
|
||||||
|
// Wait for summary to update
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
|
||||||
|
// Check that summary contains "You pay" and "you receive" with EUR amount and sats
|
||||||
|
const summaryElement = page.getByTestId("trade-summary");
|
||||||
|
await expect(summaryElement).toBeVisible({ timeout: 5000 });
|
||||||
|
const summaryText = await summaryElement.textContent();
|
||||||
|
expect(summaryText).toContain("You pay");
|
||||||
|
expect(summaryText).toContain("you receive");
|
||||||
|
expect(summaryText).toMatch(/€\s*\d+/); // Should contain EUR amount
|
||||||
|
expect(summaryText).toMatch(/\d+\s*sats/); // Should contain sats amount
|
||||||
|
|
||||||
|
// Test SELL direction summary
|
||||||
|
const sellButton = page.getByRole("button", { name: "Sell BTC" });
|
||||||
|
await sellButton.click();
|
||||||
|
|
||||||
|
// Wait for summary to update
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
|
||||||
|
// Check that summary contains "You pay" and "you receive" with sats and EUR amount
|
||||||
|
const summaryTextSell = await summaryElement.textContent();
|
||||||
|
expect(summaryTextSell).toContain("You pay");
|
||||||
|
expect(summaryTextSell).toContain("you receive");
|
||||||
|
expect(summaryTextSell).toMatch(/€\s*\d+/); // Should contain EUR amount
|
||||||
|
expect(summaryTextSell).toMatch(/\d+\s*sats/); // Should contain sats amount
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
test.describe("Exchange Page - With Availability", () => {
|
test.describe("Exchange Page - With Availability", () => {
|
||||||
|
|
|
||||||
|
|
@ -114,12 +114,12 @@
|
||||||
"title": "Configuració de Preus",
|
"title": "Configuració de Preus",
|
||||||
"subtitle": "Configura els preus de prima i els límits d'import de les operacions",
|
"subtitle": "Configura els preus de prima i els límits d'import de les operacions",
|
||||||
"premiumSettings": "Configuració de Prima",
|
"premiumSettings": "Configuració de Prima",
|
||||||
"premiumBuy": "Prima per COMPRAR",
|
"premiumBuy": "Prima quan l'Usuari Compra BTC (Usuari paga EUR, rep BTC)",
|
||||||
"premiumSell": "Prima per VENDRE",
|
"premiumSell": "Prima quan l'Usuari Vén BTC (Usuari paga BTC, rep EUR)",
|
||||||
"smallTradeThreshold": "Umbral d'Operacions Petites",
|
"smallTradeThreshold": "Umbral d'Operacions Petites",
|
||||||
"smallTradeExtraPremium": "Prima Extra per Operacions Petites",
|
"smallTradeExtraPremium": "Prima Extra per Operacions Petites",
|
||||||
"tradeLimitsBuy": "Límits d'Import d'Operacions (COMPRAR)",
|
"tradeLimitsBuy": "Límits d'Import en Comprar BTC (EUR pagat per l'usuari)",
|
||||||
"tradeLimitsSell": "Límits d'Import d'Operacions (VENDRE)",
|
"tradeLimitsSell": "Límits d'Import en Vendre BTC (EUR rebut per l'usuari)",
|
||||||
"minAmount": "Import Mínim",
|
"minAmount": "Import Mínim",
|
||||||
"maxAmount": "Import Màxim",
|
"maxAmount": "Import Màxim",
|
||||||
"save": "Guardar Canvis",
|
"save": "Guardar Canvis",
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,8 @@
|
||||||
"required": "*",
|
"required": "*",
|
||||||
"lightningThreshold": "Els pagaments Lightning només estan disponibles per importants fins a €{max}",
|
"lightningThreshold": "Els pagaments Lightning només estan disponibles per importants fins a €{max}",
|
||||||
"amount": "Quantitat (EUR)",
|
"amount": "Quantitat (EUR)",
|
||||||
"summaryBuy": "Compres {sats}, vens {eur}",
|
"summaryBuy": "Pagues {eur}, reps {sats}",
|
||||||
"summarySell": "Compres {eur}, vens {sats}",
|
"summarySell": "Pagues {sats}, reps {eur}",
|
||||||
"continueToBooking": "Continuar a reserva"
|
"continueToBooking": "Continuar a reserva"
|
||||||
},
|
},
|
||||||
"bookingStep": {
|
"bookingStep": {
|
||||||
|
|
|
||||||
|
|
@ -114,12 +114,12 @@
|
||||||
"title": "Pricing Configuration",
|
"title": "Pricing Configuration",
|
||||||
"subtitle": "Configure premium pricing and trade amount limits",
|
"subtitle": "Configure premium pricing and trade amount limits",
|
||||||
"premiumSettings": "Premium Settings",
|
"premiumSettings": "Premium Settings",
|
||||||
"premiumBuy": "Premium for BUY",
|
"premiumBuy": "Premium when User Buys BTC (User pays EUR, receives BTC)",
|
||||||
"premiumSell": "Premium for SELL",
|
"premiumSell": "Premium when User Sells BTC (User pays BTC, receives EUR)",
|
||||||
"smallTradeThreshold": "Small Trade Threshold",
|
"smallTradeThreshold": "Small Trade Threshold",
|
||||||
"smallTradeExtraPremium": "Extra Premium for Small Trades",
|
"smallTradeExtraPremium": "Extra Premium for Small Trades",
|
||||||
"tradeLimitsBuy": "Trade Amount Limits (BUY)",
|
"tradeLimitsBuy": "Trade Amount Limits when Buying BTC (EUR paid by user)",
|
||||||
"tradeLimitsSell": "Trade Amount Limits (SELL)",
|
"tradeLimitsSell": "Trade Amount Limits when Selling BTC (EUR received by user)",
|
||||||
"minAmount": "Minimum Amount",
|
"minAmount": "Minimum Amount",
|
||||||
"maxAmount": "Maximum Amount",
|
"maxAmount": "Maximum Amount",
|
||||||
"save": "Save Changes",
|
"save": "Save Changes",
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,8 @@
|
||||||
"required": "*",
|
"required": "*",
|
||||||
"lightningThreshold": "Lightning payments are only available for amounts up to €{max}",
|
"lightningThreshold": "Lightning payments are only available for amounts up to €{max}",
|
||||||
"amount": "Amount (EUR)",
|
"amount": "Amount (EUR)",
|
||||||
"summaryBuy": "You buy {sats}, you sell {eur}",
|
"summaryBuy": "You pay {eur}, you receive {sats}",
|
||||||
"summarySell": "You buy {eur}, you sell {sats}",
|
"summarySell": "You pay {sats}, you receive {eur}",
|
||||||
"continueToBooking": "Continue to Booking"
|
"continueToBooking": "Continue to Booking"
|
||||||
},
|
},
|
||||||
"bookingStep": {
|
"bookingStep": {
|
||||||
|
|
|
||||||
|
|
@ -114,12 +114,12 @@
|
||||||
"title": "Configuración de Precios",
|
"title": "Configuración de Precios",
|
||||||
"subtitle": "Configura los precios de prima y los límites de importe de las operaciones",
|
"subtitle": "Configura los precios de prima y los límites de importe de las operaciones",
|
||||||
"premiumSettings": "Configuración de Prima",
|
"premiumSettings": "Configuración de Prima",
|
||||||
"premiumBuy": "Prima para COMPRAR",
|
"premiumBuy": "Prima cuando el Usuario Compra BTC (Usuario paga EUR, recibe BTC)",
|
||||||
"premiumSell": "Prima para VENDER",
|
"premiumSell": "Prima cuando el Usuario Vende BTC (Usuario paga BTC, recibe EUR)",
|
||||||
"smallTradeThreshold": "Umbral de Operaciones Pequeñas",
|
"smallTradeThreshold": "Umbral de Operaciones Pequeñas",
|
||||||
"smallTradeExtraPremium": "Prima Extra para Operaciones Pequeñas",
|
"smallTradeExtraPremium": "Prima Extra para Operaciones Pequeñas",
|
||||||
"tradeLimitsBuy": "Límites de Importe de Operaciones (COMPRAR)",
|
"tradeLimitsBuy": "Límites de Importe al Comprar BTC (EUR pagado por el usuario)",
|
||||||
"tradeLimitsSell": "Límites de Importe de Operaciones (VENDER)",
|
"tradeLimitsSell": "Límites de Importe al Vender BTC (EUR recibido por el usuario)",
|
||||||
"minAmount": "Importe Mínimo",
|
"minAmount": "Importe Mínimo",
|
||||||
"maxAmount": "Importe Máximo",
|
"maxAmount": "Importe Máximo",
|
||||||
"save": "Guardar Cambios",
|
"save": "Guardar Cambios",
|
||||||
|
|
|
||||||
|
|
@ -31,8 +31,8 @@
|
||||||
"required": "*",
|
"required": "*",
|
||||||
"lightningThreshold": "Los pagos Lightning solo están disponibles para montos de hasta €{max}",
|
"lightningThreshold": "Los pagos Lightning solo están disponibles para montos de hasta €{max}",
|
||||||
"amount": "Cantidad (EUR)",
|
"amount": "Cantidad (EUR)",
|
||||||
"summaryBuy": "Compras {sats}, vendes {eur}",
|
"summaryBuy": "Pagas {eur}, recibes {sats}",
|
||||||
"summarySell": "Compras {eur}, vendes {sats}",
|
"summarySell": "Pagas {sats}, recibes {eur}",
|
||||||
"continueToBooking": "Continuar a reserva"
|
"continueToBooking": "Continuar a reserva"
|
||||||
},
|
},
|
||||||
"bookingStep": {
|
"bookingStep": {
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@
|
||||||
"slotDurationMinutes": 15,
|
"slotDurationMinutes": 15,
|
||||||
"maxAdvanceDays": 30,
|
"maxAdvanceDays": 30,
|
||||||
"minAdvanceDays": 1,
|
"minAdvanceDays": 1,
|
||||||
"eurTradeIncrement": 20,
|
"eurTradeIncrement": 5,
|
||||||
"priceRefreshSeconds": 60,
|
"priceRefreshSeconds": 60,
|
||||||
"priceStalenessSeconds": 300,
|
"priceStalenessSeconds": 300,
|
||||||
"lightningMaxEur": 1000
|
"lightningMaxEur": 1000
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue