style: align AdminTariffCreate with other admin create pages

Added gap-3 to footer for consistency with AdminCampaignCreate
and AdminBroadcastCreate pages
This commit is contained in:
c0mrade
2026-02-02 01:49:04 +03:00
parent dc17695206
commit 1ca34fa3d1

View File

@@ -46,7 +46,7 @@ const InfinityIcon = () => (
); );
const CalendarIcon = () => ( const CalendarIcon = () => (
<svg className="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}> <svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
<path <path
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
@@ -56,7 +56,7 @@ const CalendarIcon = () => (
); );
const SunIcon = () => ( const SunIcon = () => (
<svg className="h-8 w-8" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}> <svg className="h-6 w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
<path <path
strokeLinecap="round" strokeLinecap="round"
strokeLinejoin="round" strokeLinejoin="round"
@@ -65,6 +65,22 @@ const SunIcon = () => (
</svg> </svg>
); );
const RefreshIcon = () => (
<svg
className="h-4 w-4 animate-spin"
fill="none"
viewBox="0 0 24 24"
stroke="currentColor"
strokeWidth={2}
>
<path
strokeLinecap="round"
strokeLinejoin="round"
d="M16.023 9.348h4.992v-.001M2.985 19.644v-4.992m0 0h4.992m-4.993 0l3.181 3.183a8.25 8.25 0 0013.803-3.7M4.031 9.865a8.25 8.25 0 0113.803-3.7l3.181 3.182m0-4.991v4.99"
/>
</svg>
);
type TariffType = 'period' | 'daily' | null; type TariffType = 'period' | 'daily' | null;
export default function AdminTariffCreate() { export default function AdminTariffCreate() {
@@ -131,7 +147,6 @@ export default function AdminTariffCreate() {
refetchOnMount: true, refetchOnMount: true,
refetchOnWindowFocus: false, refetchOnWindowFocus: false,
select: useCallback((data: TariffDetail) => { select: useCallback((data: TariffDetail) => {
// Set form values from tariff
setTariffType(data.is_daily ? 'daily' : 'period'); setTariffType(data.is_daily ? 'daily' : 'period');
setName(data.name); setName(data.name);
setDescription(data.description || ''); setDescription(data.description || '');
@@ -199,7 +214,6 @@ export default function AdminTariffCreate() {
traffic_reset_mode: trafficResetMode, traffic_reset_mode: trafficResetMode,
}; };
// Add period tariff specific fields
if (!isDaily) { if (!isDaily) {
data.custom_days_enabled = customDaysEnabled; data.custom_days_enabled = customDaysEnabled;
data.price_per_day_kopeks = pricePerDayKopeks; data.price_per_day_kopeks = pricePerDayKopeks;
@@ -268,11 +282,11 @@ export default function AdminTariffCreate() {
// Type selection step (only for creation) // Type selection step (only for creation)
if (!isEdit && tariffType === null) { if (!isEdit && tariffType === null) {
return ( return (
<div className="animate-fade-in"> <div className="space-y-6">
<div className="mb-6 flex items-center gap-3"> <div className="flex items-center gap-3">
<AdminBackButton /> <AdminBackButton />
<div> <div>
<h1 className="text-xl font-semibold text-dark-100">{t('admin.tariffs.selectType')}</h1> <h1 className="text-xl font-bold text-dark-100">{t('admin.tariffs.selectType')}</h1>
<p className="text-sm text-dark-400">{t('admin.tariffs.selectTypeDesc')}</p> <p className="text-sm text-dark-400">{t('admin.tariffs.selectTypeDesc')}</p>
</div> </div>
</div> </div>
@@ -280,7 +294,7 @@ export default function AdminTariffCreate() {
<div className="grid gap-4 sm:grid-cols-2"> <div className="grid gap-4 sm:grid-cols-2">
<button <button
onClick={() => setTariffType('period')} onClick={() => setTariffType('period')}
className="group rounded-xl bg-dark-800 p-6 text-left transition-colors hover:bg-dark-700" className="card group p-6 text-left transition-colors hover:border-accent-500/50"
> >
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="rounded-lg bg-accent-500/20 p-3 text-accent-400 group-hover:bg-accent-500/30"> <div className="rounded-lg bg-accent-500/20 p-3 text-accent-400 group-hover:bg-accent-500/30">
@@ -294,7 +308,7 @@ export default function AdminTariffCreate() {
</button> </button>
<button <button
onClick={() => setTariffType('daily')} onClick={() => setTariffType('daily')}
className="group rounded-xl bg-dark-800 p-6 text-left transition-colors hover:bg-dark-700" className="card group p-6 text-left transition-colors hover:border-warning-500/50"
> >
<div className="flex items-center gap-4"> <div className="flex items-center gap-4">
<div className="rounded-lg bg-warning-500/20 p-3 text-warning-400 group-hover:bg-warning-500/30"> <div className="rounded-lg bg-warning-500/20 p-3 text-warning-400 group-hover:bg-warning-500/30">
@@ -315,23 +329,23 @@ export default function AdminTariffCreate() {
const accentColor = isDaily ? 'warning' : 'accent'; const accentColor = isDaily ? 'warning' : 'accent';
return ( return (
<div className="animate-fade-in"> <div className="space-y-6">
{/* Header */} {/* Header */}
<div className="mb-6 flex items-center gap-3"> <div className="flex items-center gap-3">
<AdminBackButton /> <AdminBackButton />
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<div className={`rounded-lg bg-${accentColor}-500/20 p-2 text-${accentColor}-400`}> <div className={`rounded-lg bg-${accentColor}-500/20 p-2 text-${accentColor}-400`}>
{isDaily ? <SunIcon /> : <CalendarIcon />} {isDaily ? <SunIcon /> : <CalendarIcon />}
</div> </div>
<div> <div>
<h1 className="text-xl font-semibold text-dark-100"> <h1 className="text-xl font-bold text-dark-100">
{isEdit {isEdit
? t('admin.tariffs.editTitle') ? t('admin.tariffs.editTitle')
: isDaily : isDaily
? t('admin.tariffs.newDailyTitle') ? t('admin.tariffs.newDailyTitle')
: t('admin.tariffs.newPeriodTitle')} : t('admin.tariffs.newPeriodTitle')}
</h1> </h1>
<p className="text-xs text-dark-500"> <p className="text-sm text-dark-400">
{isDaily ? t('admin.tariffs.dailyDeduction') : t('admin.tariffs.periodPayment')} {isDaily ? t('admin.tariffs.dailyDeduction') : t('admin.tariffs.periodPayment')}
</p> </p>
</div> </div>
@@ -340,7 +354,7 @@ export default function AdminTariffCreate() {
{/* Tabs */} {/* Tabs */}
<div <div
className="scrollbar-hide -mx-4 mb-6 flex gap-2 overflow-x-auto px-4 py-1" className="scrollbar-hide -mx-4 flex gap-2 overflow-x-auto px-4 py-1"
style={{ WebkitOverflowScrolling: 'touch' }} style={{ WebkitOverflowScrolling: 'touch' }}
> >
{(isDaily {(isDaily
@@ -353,7 +367,7 @@ export default function AdminTariffCreate() {
className={`shrink-0 whitespace-nowrap rounded-xl px-4 py-2.5 text-sm font-medium transition-all ${ className={`shrink-0 whitespace-nowrap rounded-xl px-4 py-2.5 text-sm font-medium transition-all ${
activeTab === tab activeTab === tab
? `bg-${accentColor}-500/15 text-${accentColor}-400 ring-1 ring-${accentColor}-500/30` ? `bg-${accentColor}-500/15 text-${accentColor}-400 ring-1 ring-${accentColor}-500/30`
: 'bg-dark-800/50 text-dark-400 active:bg-dark-700' : 'bg-dark-800/50 text-dark-400 hover:bg-dark-700'
}`} }`}
> >
{tab === 'basic' && t('admin.tariffs.tabBasic')} {tab === 'basic' && t('admin.tariffs.tabBasic')}
@@ -365,44 +379,40 @@ export default function AdminTariffCreate() {
</div> </div>
{/* Content */} {/* Content */}
<div className="space-y-6">
{activeTab === 'basic' && ( {activeTab === 'basic' && (
<div className="space-y-4"> <div className="card space-y-4">
{/* Name */} {/* Name */}
<div className="rounded-xl bg-dark-800 p-4"> <div>
<label className="mb-1 block text-sm text-dark-300"> <label className="mb-2 block text-sm font-medium text-dark-300">
{t('admin.tariffs.nameLabel')} {t('admin.tariffs.nameLabel')}
</label> </label>
<input <input
type="text" type="text"
value={name} value={name}
onChange={(e) => setName(e.target.value)} onChange={(e) => setName(e.target.value)}
className="w-full rounded-lg border border-dark-600 bg-dark-700 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input"
placeholder={ placeholder={
isDaily isDaily ? t('admin.tariffs.nameExampleDaily') : t('admin.tariffs.nameExamplePeriod')
? t('admin.tariffs.nameExampleDaily')
: t('admin.tariffs.nameExamplePeriod')
} }
/> />
</div> </div>
{/* Description */} {/* Description */}
<div className="rounded-xl bg-dark-800 p-4"> <div>
<label className="mb-1 block text-sm text-dark-300"> <label className="mb-2 block text-sm font-medium text-dark-300">
{t('admin.tariffs.descriptionLabel')} {t('admin.tariffs.descriptionLabel')}
</label> </label>
<textarea <textarea
value={description} value={description}
onChange={(e) => setDescription(e.target.value)} onChange={(e) => setDescription(e.target.value)}
className="w-full resize-none rounded-lg border border-dark-600 bg-dark-700 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input min-h-[80px] resize-none"
rows={2}
placeholder={t('admin.tariffs.descriptionPlaceholder')} placeholder={t('admin.tariffs.descriptionPlaceholder')}
/> />
</div> </div>
{/* Daily Price (only for daily tariff) */} {/* Daily Price (only for daily tariff) */}
{isDaily && ( {isDaily && (
<div className="rounded-xl border border-warning-500/30 bg-warning-500/10 p-4"> <div className="rounded-lg border border-warning-500/30 bg-warning-500/10 p-4">
<label className="mb-2 block text-sm font-medium text-warning-400"> <label className="mb-2 block text-sm font-medium text-warning-400">
{t('admin.tariffs.dailyPriceLabel')} {t('admin.tariffs.dailyPriceLabel')}
</label> </label>
@@ -413,21 +423,19 @@ export default function AdminTariffCreate() {
onChange={(e) => onChange={(e) =>
setDailyPriceKopeks(Math.max(0, parseFloat(e.target.value) || 0) * 100) setDailyPriceKopeks(Math.max(0, parseFloat(e.target.value) || 0) * 100)
} }
className="w-32 rounded-lg border border-dark-600 bg-dark-700 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input w-32"
min={0} min={0}
step={0.1} step={0.1}
/> />
<span className="text-dark-400">{t('admin.tariffs.currencyPerDay')}</span> <span className="text-dark-400">{t('admin.tariffs.currencyPerDay')}</span>
</div> </div>
<p className="mt-2 text-xs text-dark-500"> <p className="mt-2 text-xs text-dark-500">{t('admin.tariffs.dailyDeductionDesc')}</p>
{t('admin.tariffs.dailyDeductionDesc')}
</p>
</div> </div>
)} )}
{/* Traffic Limit */} {/* Traffic Limit */}
<div className="rounded-xl bg-dark-800 p-4"> <div>
<label className="mb-1 block text-sm text-dark-300"> <label className="mb-2 block text-sm font-medium text-dark-300">
{t('admin.tariffs.trafficLimitLabel')} {t('admin.tariffs.trafficLimitLabel')}
</label> </label>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2">
@@ -435,7 +443,7 @@ export default function AdminTariffCreate() {
type="number" type="number"
value={trafficLimitGb} value={trafficLimitGb}
onChange={(e) => setTrafficLimitGb(Math.max(0, parseInt(e.target.value) || 0))} onChange={(e) => setTrafficLimitGb(Math.max(0, parseInt(e.target.value) || 0))}
className="w-32 rounded-lg border border-dark-600 bg-dark-700 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input w-32"
min={0} min={0}
/> />
<span className="text-dark-400">{t('admin.tariffs.gbUnit')}</span> <span className="text-dark-400">{t('admin.tariffs.gbUnit')}</span>
@@ -450,22 +458,22 @@ export default function AdminTariffCreate() {
</div> </div>
{/* Device Limit */} {/* Device Limit */}
<div className="rounded-xl bg-dark-800 p-4"> <div>
<label className="mb-1 block text-sm text-dark-300"> <label className="mb-2 block text-sm font-medium text-dark-300">
{t('admin.tariffs.deviceLimitLabel')} {t('admin.tariffs.deviceLimitLabel')}
</label> </label>
<input <input
type="number" type="number"
value={deviceLimit} value={deviceLimit}
onChange={(e) => setDeviceLimit(Math.max(1, parseInt(e.target.value) || 1))} onChange={(e) => setDeviceLimit(Math.max(1, parseInt(e.target.value) || 1))}
className="w-32 rounded-lg border border-dark-600 bg-dark-700 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input w-32"
min={1} min={1}
/> />
</div> </div>
{/* Tier Level */} {/* Tier Level */}
<div className="rounded-xl bg-dark-800 p-4"> <div>
<label className="mb-1 block text-sm text-dark-300"> <label className="mb-2 block text-sm font-medium text-dark-300">
{t('admin.tariffs.tierLevelLabel')} {t('admin.tariffs.tierLevelLabel')}
</label> </label>
<input <input
@@ -474,7 +482,7 @@ export default function AdminTariffCreate() {
onChange={(e) => onChange={(e) =>
setTierLevel(Math.min(10, Math.max(1, parseInt(e.target.value) || 1))) setTierLevel(Math.min(10, Math.max(1, parseInt(e.target.value) || 1)))
} }
className="w-32 rounded-lg border border-dark-600 bg-dark-700 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input w-32"
min={1} min={1}
max={10} max={10}
/> />
@@ -484,11 +492,11 @@ export default function AdminTariffCreate() {
)} )}
{activeTab === 'periods' && !isDaily && ( {activeTab === 'periods' && !isDaily && (
<div className="space-y-4"> <div className="card space-y-4">
<p className="text-sm text-dark-400">{t('admin.tariffs.periodsTabHint')}</p> <p className="text-sm text-dark-400">{t('admin.tariffs.periodsTabHint')}</p>
{/* Add new period */} {/* Add new period */}
<div className="rounded-xl border border-dashed border-dark-600 bg-dark-800/50 p-4"> <div className="rounded-lg border border-dashed border-dark-600 bg-dark-800/50 p-4">
<h4 className="mb-3 text-sm font-medium text-dark-300"> <h4 className="mb-3 text-sm font-medium text-dark-300">
{t('admin.tariffs.addPeriodTitle')} {t('admin.tariffs.addPeriodTitle')}
</h4> </h4>
@@ -501,7 +509,7 @@ export default function AdminTariffCreate() {
type="number" type="number"
value={newPeriodDays} value={newPeriodDays}
onChange={(e) => setNewPeriodDays(Math.max(1, parseInt(e.target.value) || 1))} onChange={(e) => setNewPeriodDays(Math.max(1, parseInt(e.target.value) || 1))}
className="w-24 rounded-lg border border-dark-500 bg-dark-600 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input w-24"
min={1} min={1}
/> />
</div> </div>
@@ -513,14 +521,14 @@ export default function AdminTariffCreate() {
type="number" type="number"
value={newPeriodPrice} value={newPeriodPrice}
onChange={(e) => setNewPeriodPrice(Math.max(1, parseInt(e.target.value) || 1))} onChange={(e) => setNewPeriodPrice(Math.max(1, parseInt(e.target.value) || 1))}
className="w-28 rounded-lg border border-dark-500 bg-dark-600 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input w-28"
min={1} min={1}
/> />
</div> </div>
<button <button
onClick={addPeriod} onClick={addPeriod}
disabled={periodPrices.some((p) => p.days === newPeriodDays)} disabled={periodPrices.some((p) => p.days === newPeriodDays)}
className="flex items-center gap-2 rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50" className="btn-primary flex items-center gap-2"
> >
<PlusIcon /> <PlusIcon />
{t('admin.tariffs.addButton')} {t('admin.tariffs.addButton')}
@@ -530,15 +538,13 @@ export default function AdminTariffCreate() {
{/* Period list */} {/* Period list */}
{periodPrices.length === 0 ? ( {periodPrices.length === 0 ? (
<div className="py-8 text-center text-dark-500"> <div className="py-8 text-center text-dark-500">{t('admin.tariffs.noPeriodsHint')}</div>
{t('admin.tariffs.noPeriodsHint')}
</div>
) : ( ) : (
<div className="space-y-2"> <div className="space-y-2">
{periodPrices.map((period) => ( {periodPrices.map((period) => (
<div <div
key={period.days} key={period.days}
className="flex items-center gap-3 rounded-xl bg-dark-800 p-3" className="flex items-center gap-3 rounded-lg bg-dark-800 p-3"
> >
<div className="w-20 font-medium text-dark-300"> <div className="w-20 font-medium text-dark-300">
{period.days} {t('admin.tariffs.daysShort')} {period.days} {t('admin.tariffs.daysShort')}
@@ -549,7 +555,7 @@ export default function AdminTariffCreate() {
onChange={(e) => onChange={(e) =>
updatePeriodPrice(period.days, Math.max(0, parseFloat(e.target.value) || 0)) updatePeriodPrice(period.days, Math.max(0, parseFloat(e.target.value) || 0))
} }
className="w-28 rounded-lg border border-dark-500 bg-dark-600 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input w-28"
min={0} min={0}
step={1} step={1}
/> />
@@ -569,26 +575,27 @@ export default function AdminTariffCreate() {
)} )}
{activeTab === 'servers' && ( {activeTab === 'servers' && (
<div className="space-y-2"> <div className="card space-y-4">
<p className="mb-4 text-sm text-dark-400">{t('admin.tariffs.serversTabHint')}</p> <p className="text-sm text-dark-400">{t('admin.tariffs.serversTabHint')}</p>
{servers.length === 0 ? ( {servers.length === 0 ? (
<p className="py-4 text-center text-dark-500"> <p className="py-4 text-center text-dark-500">
{t('admin.tariffs.noServersAvailable')} {t('admin.tariffs.noServersAvailable')}
</p> </p>
) : ( ) : (
servers.map((server: ServerInfo) => { <div className="max-h-64 space-y-2 overflow-y-auto">
{servers.map((server: ServerInfo) => {
const isSelected = selectedSquads.includes(server.squad_uuid); const isSelected = selectedSquads.includes(server.squad_uuid);
return ( return (
<div <button
key={server.id} key={server.id}
type="button"
onClick={() => toggleServer(server.squad_uuid)} onClick={() => toggleServer(server.squad_uuid)}
className={`cursor-pointer rounded-xl p-3 transition-colors ${ className={`flex w-full items-center gap-3 rounded-lg p-3 text-left transition-colors ${
isSelected isSelected
? `border border-${accentColor}-500/50 bg-${accentColor}-500/20` ? `bg-${accentColor}-500/20 text-${accentColor}-300`
: 'border border-transparent bg-dark-800 hover:bg-dark-700' : 'bg-dark-800 text-dark-300 hover:bg-dark-700'
}`} }`}
> >
<div className="flex items-center gap-3">
<div <div
className={`flex h-5 w-5 items-center justify-center rounded ${ className={`flex h-5 w-5 items-center justify-center rounded ${
isSelected ? 'bg-accent-500 text-white' : 'bg-dark-600' isSelected ? 'bg-accent-500 text-white' : 'bg-dark-600'
@@ -596,26 +603,25 @@ export default function AdminTariffCreate() {
> >
{isSelected && <CheckIcon />} {isSelected && <CheckIcon />}
</div> </div>
<span className="flex-1 text-dark-200">{server.display_name}</span> <span className="flex-1 text-sm font-medium">{server.display_name}</span>
{server.country_code && ( {server.country_code && (
<span className="text-xs text-dark-500">{server.country_code}</span> <span className="text-xs text-dark-500">{server.country_code}</span>
)} )}
</div> </button>
</div>
); );
}) })}
</div>
)} )}
</div> </div>
)} )}
{activeTab === 'extra' && ( {activeTab === 'extra' && (
<div className="space-y-6"> <div className="space-y-4">
{/* Device addon */} {/* Device addon */}
<div className="rounded-xl bg-dark-800 p-4"> <div className="card space-y-3">
<h4 className="mb-3 text-sm font-medium text-dark-200"> <h4 className="text-sm font-medium text-dark-200">
{t('admin.tariffs.extraDeviceTitle')} {t('admin.tariffs.extraDeviceTitle')}
</h4> </h4>
<div className="space-y-3">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<span className="w-48 text-sm text-dark-400"> <span className="w-48 text-sm text-dark-400">
{t('admin.tariffs.devicePriceLabel')} {t('admin.tariffs.devicePriceLabel')}
@@ -626,7 +632,7 @@ export default function AdminTariffCreate() {
onChange={(e) => onChange={(e) =>
setDevicePriceKopeks(Math.max(0, parseFloat(e.target.value) || 0) * 100) setDevicePriceKopeks(Math.max(0, parseFloat(e.target.value) || 0) * 100)
} }
className="w-24 rounded-lg border border-dark-500 bg-dark-600 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input w-24"
min={0} min={0}
step={1} step={1}
/> />
@@ -641,36 +647,35 @@ export default function AdminTariffCreate() {
type="number" type="number"
value={maxDeviceLimit} value={maxDeviceLimit}
onChange={(e) => setMaxDeviceLimit(Math.max(0, parseInt(e.target.value) || 0))} onChange={(e) => setMaxDeviceLimit(Math.max(0, parseInt(e.target.value) || 0))}
className="w-24 rounded-lg border border-dark-500 bg-dark-600 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input w-24"
min={0} min={0}
/> />
</div> </div>
<p className="text-xs text-dark-500">{t('admin.tariffs.noLimitHint')}</p> <p className="text-xs text-dark-500">{t('admin.tariffs.noLimitHint')}</p>
</div> </div>
</div>
{/* Traffic topup */} {/* Traffic topup */}
<div className="rounded-xl bg-dark-800 p-4"> <div className="card space-y-3">
<div className="mb-3 flex items-center justify-between"> <div className="flex items-center justify-between">
<h4 className="text-sm font-medium text-dark-200"> <h4 className="text-sm font-medium text-dark-200">
{t('admin.tariffs.extraTrafficTitle')} {t('admin.tariffs.extraTrafficTitle')}
</h4> </h4>
<button <button
type="button" type="button"
onClick={() => setTrafficTopupEnabled(!trafficTopupEnabled)} onClick={() => setTrafficTopupEnabled(!trafficTopupEnabled)}
className={`relative h-6 w-10 rounded-full transition-colors ${ className={`relative h-6 w-11 rounded-full transition-colors ${
trafficTopupEnabled ? `bg-${accentColor}-500` : 'bg-dark-600' trafficTopupEnabled ? 'bg-accent-500' : 'bg-dark-600'
}`} }`}
> >
<span <span
className={`absolute top-1 h-4 w-4 rounded-full bg-white transition-transform ${ className={`absolute top-1 h-4 w-4 rounded-full bg-white transition-transform ${
trafficTopupEnabled ? 'left-5' : 'left-1' trafficTopupEnabled ? 'left-6' : 'left-1'
}`} }`}
/> />
</button> </button>
</div> </div>
{trafficTopupEnabled && ( {trafficTopupEnabled && (
<div className="space-y-3"> <>
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<span className="w-32 text-sm text-dark-400"> <span className="w-32 text-sm text-dark-400">
{t('admin.tariffs.trafficMaxLimitLabel')} {t('admin.tariffs.trafficMaxLimitLabel')}
@@ -681,15 +686,12 @@ export default function AdminTariffCreate() {
onChange={(e) => onChange={(e) =>
setMaxTopupTrafficGb(Math.max(0, parseInt(e.target.value) || 0)) setMaxTopupTrafficGb(Math.max(0, parseInt(e.target.value) || 0))
} }
className="w-24 rounded-lg border border-dark-500 bg-dark-600 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input w-24"
min={0} min={0}
/> />
<span className="text-dark-400">{t('admin.tariffs.gbUnit')}</span> <span className="text-dark-400">{t('admin.tariffs.gbUnit')}</span>
<span className="text-xs text-dark-500">
{t('admin.tariffs.trafficLimitHint2')}
</span>
</div> </div>
<div className="mt-3"> <div>
<span className="text-sm text-dark-400"> <span className="text-sm text-dark-400">
{t('admin.tariffs.trafficPackagesLabel')} {t('admin.tariffs.trafficPackagesLabel')}
</span> </span>
@@ -709,7 +711,7 @@ export default function AdminTariffCreate() {
[String(gb)]: price, [String(gb)]: price,
})); }));
}} }}
className="w-20 rounded border border-dark-500 bg-dark-600 px-2 py-1 text-sm text-dark-100 focus:border-accent-500 focus:outline-none" className="input w-20"
min={0} min={0}
step={1} step={1}
/> />
@@ -718,38 +720,36 @@ export default function AdminTariffCreate() {
))} ))}
</div> </div>
</div> </div>
</div> </>
)} )}
</div> </div>
{/* Custom days (period only) */} {/* Custom days (period only) */}
{!isDaily && ( {!isDaily && (
<div className="rounded-xl bg-dark-800 p-4"> <div className="card space-y-3">
<div className="mb-3 flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h4 className="text-sm font-medium text-dark-200"> <h4 className="text-sm font-medium text-dark-200">
{t('admin.tariffs.customDaysTitle')} {t('admin.tariffs.customDaysTitle')}
</h4> </h4>
<p className="mt-1 text-xs text-dark-500"> <p className="mt-1 text-xs text-dark-500">{t('admin.tariffs.customDaysDesc')}</p>
{t('admin.tariffs.customDaysDesc')}
</p>
</div> </div>
<button <button
type="button" type="button"
onClick={() => setCustomDaysEnabled(!customDaysEnabled)} onClick={() => setCustomDaysEnabled(!customDaysEnabled)}
className={`relative h-6 w-10 rounded-full transition-colors ${ className={`relative h-6 w-11 rounded-full transition-colors ${
customDaysEnabled ? 'bg-accent-500' : 'bg-dark-600' customDaysEnabled ? 'bg-accent-500' : 'bg-dark-600'
}`} }`}
> >
<span <span
className={`absolute top-1 h-4 w-4 rounded-full bg-white transition-transform ${ className={`absolute top-1 h-4 w-4 rounded-full bg-white transition-transform ${
customDaysEnabled ? 'left-5' : 'left-1' customDaysEnabled ? 'left-6' : 'left-1'
}`} }`}
/> />
</button> </button>
</div> </div>
{customDaysEnabled && ( {customDaysEnabled && (
<div className="space-y-3 border-t border-dark-600 pt-2"> <div className="space-y-3 border-t border-dark-700 pt-3">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<span className="w-32 text-sm text-dark-400"> <span className="w-32 text-sm text-dark-400">
{t('admin.tariffs.pricePerDayLabel')} {t('admin.tariffs.pricePerDayLabel')}
@@ -760,7 +760,7 @@ export default function AdminTariffCreate() {
onChange={(e) => onChange={(e) =>
setPricePerDayKopeks(Math.max(0, parseFloat(e.target.value) || 0) * 100) setPricePerDayKopeks(Math.max(0, parseFloat(e.target.value) || 0) * 100)
} }
className="w-24 rounded-lg border border-dark-500 bg-dark-600 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input w-24"
min={0} min={0}
step={0.1} step={0.1}
/> />
@@ -774,7 +774,7 @@ export default function AdminTariffCreate() {
type="number" type="number"
value={minDays} value={minDays}
onChange={(e) => setMinDays(Math.max(1, parseInt(e.target.value) || 1))} onChange={(e) => setMinDays(Math.max(1, parseInt(e.target.value) || 1))}
className="w-24 rounded-lg border border-dark-500 bg-dark-600 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input w-24"
min={1} min={1}
/> />
</div> </div>
@@ -786,7 +786,7 @@ export default function AdminTariffCreate() {
type="number" type="number"
value={maxDays} value={maxDays}
onChange={(e) => setMaxDays(Math.max(1, parseInt(e.target.value) || 1))} onChange={(e) => setMaxDays(Math.max(1, parseInt(e.target.value) || 1))}
className="w-24 rounded-lg border border-dark-500 bg-dark-600 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input w-24"
min={1} min={1}
/> />
</div> </div>
@@ -797,8 +797,8 @@ export default function AdminTariffCreate() {
{/* Custom traffic (period only) */} {/* Custom traffic (period only) */}
{!isDaily && ( {!isDaily && (
<div className="rounded-xl bg-dark-800 p-4"> <div className="card space-y-3">
<div className="mb-3 flex items-center justify-between"> <div className="flex items-center justify-between">
<div> <div>
<h4 className="text-sm font-medium text-dark-200"> <h4 className="text-sm font-medium text-dark-200">
{t('admin.tariffs.customTrafficTitle')} {t('admin.tariffs.customTrafficTitle')}
@@ -810,19 +810,19 @@ export default function AdminTariffCreate() {
<button <button
type="button" type="button"
onClick={() => setCustomTrafficEnabled(!customTrafficEnabled)} onClick={() => setCustomTrafficEnabled(!customTrafficEnabled)}
className={`relative h-6 w-10 rounded-full transition-colors ${ className={`relative h-6 w-11 rounded-full transition-colors ${
customTrafficEnabled ? 'bg-accent-500' : 'bg-dark-600' customTrafficEnabled ? 'bg-accent-500' : 'bg-dark-600'
}`} }`}
> >
<span <span
className={`absolute top-1 h-4 w-4 rounded-full bg-white transition-transform ${ className={`absolute top-1 h-4 w-4 rounded-full bg-white transition-transform ${
customTrafficEnabled ? 'left-5' : 'left-1' customTrafficEnabled ? 'left-6' : 'left-1'
}`} }`}
/> />
</button> </button>
</div> </div>
{customTrafficEnabled && ( {customTrafficEnabled && (
<div className="space-y-3 border-t border-dark-600 pt-2"> <div className="space-y-3 border-t border-dark-700 pt-3">
<div className="flex items-center gap-3"> <div className="flex items-center gap-3">
<span className="w-32 text-sm text-dark-400"> <span className="w-32 text-sm text-dark-400">
{t('admin.tariffs.pricePerGbLabel')} {t('admin.tariffs.pricePerGbLabel')}
@@ -835,7 +835,7 @@ export default function AdminTariffCreate() {
Math.max(0, parseFloat(e.target.value) || 0) * 100, Math.max(0, parseFloat(e.target.value) || 0) * 100,
) )
} }
className="w-24 rounded-lg border border-dark-500 bg-dark-600 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none" className="input w-24"
min={0} min={0}
step={0.1} step={0.1}
/> />
@@ -848,10 +848,8 @@ export default function AdminTariffCreate() {
<input <input
type="number" type="number"
value={minTrafficGb} value={minTrafficGb}
onChange={(e) => onChange={(e) => setMinTrafficGb(Math.max(1, parseInt(e.target.value) || 1))}
setMinTrafficGb(Math.max(1, parseInt(e.target.value) || 1)) className="input w-24"
}
className="w-24 rounded-lg border border-dark-500 bg-dark-600 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none"
min={1} min={1}
/> />
</div> </div>
@@ -862,10 +860,8 @@ export default function AdminTariffCreate() {
<input <input
type="number" type="number"
value={maxTrafficGb} value={maxTrafficGb}
onChange={(e) => onChange={(e) => setMaxTrafficGb(Math.max(1, parseInt(e.target.value) || 1))}
setMaxTrafficGb(Math.max(1, parseInt(e.target.value) || 1)) className="input w-24"
}
className="w-24 rounded-lg border border-dark-500 bg-dark-600 px-3 py-2 text-dark-100 focus:border-accent-500 focus:outline-none"
min={1} min={1}
/> />
</div> </div>
@@ -875,98 +871,48 @@ export default function AdminTariffCreate() {
)} )}
{/* Traffic reset mode */} {/* Traffic reset mode */}
<div className="rounded-xl bg-dark-800 p-4"> <div className="card space-y-3">
<h4 className="mb-3 text-sm font-medium text-dark-200"> <h4 className="text-sm font-medium text-dark-200">
{t('admin.tariffs.trafficResetModeTitle')} {t('admin.tariffs.trafficResetModeTitle')}
</h4> </h4>
<p className="mb-3 text-xs text-dark-500"> <p className="text-xs text-dark-500">{t('admin.tariffs.trafficResetModeDesc')}</p>
{t('admin.tariffs.trafficResetModeDesc')} <div className="grid grid-cols-2 gap-2">
</p>
<div className="space-y-2">
{[ {[
{ { value: null, labelKey: 'admin.tariffs.resetModeGlobal', emoji: '🌐' },
value: null, { value: 'DAY', labelKey: 'admin.tariffs.resetModeDaily', emoji: '📅' },
labelKey: 'admin.tariffs.resetModeGlobal', { value: 'WEEK', labelKey: 'admin.tariffs.resetModeWeekly', emoji: '📆' },
descKey: 'admin.tariffs.resetModeGlobalDesc', { value: 'MONTH', labelKey: 'admin.tariffs.resetModeMonthly', emoji: '🗓️' },
emoji: '🌐', { value: 'NO_RESET', labelKey: 'admin.tariffs.resetModeNever', emoji: '🚫' },
},
{
value: 'DAY',
labelKey: 'admin.tariffs.resetModeDaily',
descKey: 'admin.tariffs.resetModeDailyDesc',
emoji: '📅',
},
{
value: 'WEEK',
labelKey: 'admin.tariffs.resetModeWeekly',
descKey: 'admin.tariffs.resetModeWeeklyDesc',
emoji: '📆',
},
{
value: 'MONTH',
labelKey: 'admin.tariffs.resetModeMonthly',
descKey: 'admin.tariffs.resetModeMonthlyDesc',
emoji: '🗓️',
},
{
value: 'NO_RESET',
labelKey: 'admin.tariffs.resetModeNever',
descKey: 'admin.tariffs.resetModeNeverDesc',
emoji: '🚫',
},
].map((option) => ( ].map((option) => (
<button <button
key={option.value || 'global'} key={option.value || 'global'}
type="button" type="button"
onClick={() => setTrafficResetMode(option.value)} onClick={() => setTrafficResetMode(option.value)}
className={`w-full rounded-lg p-3 text-left transition-colors ${ className={`rounded-lg p-3 text-left text-sm transition-colors ${
trafficResetMode === option.value trafficResetMode === option.value
? `border border-${accentColor}-500 bg-${accentColor}-500/20` ? `bg-${accentColor}-500/20 text-${accentColor}-300 ring-1 ring-${accentColor}-500/30`
: 'border border-dark-500 bg-dark-600 hover:border-dark-400' : 'bg-dark-800 text-dark-300 hover:bg-dark-700'
}`} }`}
> >
<div className="flex items-center justify-between">
<div>
<span className="text-sm text-dark-100">
{option.emoji} {t(option.labelKey)} {option.emoji} {t(option.labelKey)}
</span>
<p className="mt-0.5 text-xs text-dark-400">{t(option.descKey)}</p>
</div>
{trafficResetMode === option.value && (
<span className={`text-${accentColor}-400`}>
<CheckIcon />
</span>
)}
</div>
</button> </button>
))} ))}
</div> </div>
</div> </div>
</div> </div>
)} )}
</div>
{/* Footer */} {/* Footer */}
<div className="fixed inset-x-0 bottom-0 border-t border-dark-700 bg-dark-900/95 p-4 backdrop-blur-sm"> <div className="card flex items-center justify-end gap-3">
<div className="mx-auto flex max-w-2xl justify-end gap-3">
<button
onClick={() => navigate('/admin/tariffs')}
className="px-4 py-2 text-dark-300 transition-colors hover:text-dark-100"
>
{t('admin.tariffs.cancelButton')}
</button>
<button <button
onClick={handleSubmit} onClick={handleSubmit}
disabled={!isValid || isLoading} disabled={!isValid || isLoading}
className="rounded-lg bg-accent-500 px-4 py-2 text-white transition-colors hover:bg-accent-600 disabled:cursor-not-allowed disabled:opacity-50" className="btn-primary flex items-center gap-2"
> >
{isLoading && <RefreshIcon />}
{isLoading ? t('admin.tariffs.savingButton') : t('admin.tariffs.saveButton')} {isLoading ? t('admin.tariffs.savingButton') : t('admin.tariffs.saveButton')}
</button> </button>
</div> </div>
</div> </div>
{/* Spacer for fixed footer */}
<div className="h-20" />
</div>
); );
} }