fix
This commit is contained in:
@@ -29,16 +29,25 @@ import {
|
|||||||
|
|
||||||
// Default price of one Kavenegar verify SMS, in Toman. Only used to price the
|
// Default price of one Kavenegar verify SMS, in Toman. Only used to price the
|
||||||
// SMS total in the panel — the admin can change it and the choice is remembered.
|
// SMS total in the panel — the admin can change it and the choice is remembered.
|
||||||
const DEFAULT_SMS_UNIT_COST = 800;
|
const DEFAULT_SMS_UNIT_COST = 2000;
|
||||||
const SMS_COST_STORAGE_KEY = 'approagency:sms_unit_cost';
|
const SMS_COST_STORAGE_KEY = 'approagency:sms_unit_cost';
|
||||||
|
|
||||||
const emptyFilters: AuthLogFilters = {
|
// Today as the Gregorian YYYY-MM-DD the API and PersianDatePicker exchange.
|
||||||
|
const todayValue = (): string => {
|
||||||
|
const now = new Date();
|
||||||
|
const month = String(now.getMonth() + 1).padStart(2, '0');
|
||||||
|
const day = String(now.getDate()).padStart(2, '0');
|
||||||
|
return `${now.getFullYear()}-${month}-${day}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The section opens on today's activity; widen the range with the date pickers.
|
||||||
|
const createDefaultFilters = (): AuthLogFilters => ({
|
||||||
event: '',
|
event: '',
|
||||||
mobile: '',
|
mobile: '',
|
||||||
package_name: '',
|
package_name: '',
|
||||||
date_from: '',
|
date_from: todayValue(),
|
||||||
date_to: '',
|
date_to: todayValue(),
|
||||||
};
|
});
|
||||||
|
|
||||||
const eventBadgeClass = (event: string, success: boolean): string => {
|
const eventBadgeClass = (event: string, success: boolean): string => {
|
||||||
if (!success) return 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300';
|
if (!success) return 'bg-red-100 text-red-800 dark:bg-red-900/30 dark:text-red-300';
|
||||||
@@ -51,23 +60,15 @@ const eventBadgeClass = (event: string, success: boolean): string => {
|
|||||||
export default function AuthAnalyticsPage() {
|
export default function AuthAnalyticsPage() {
|
||||||
const { token } = useAuth();
|
const { token } = useAuth();
|
||||||
const [packages, setPackages] = useState<PackageName[]>([]);
|
const [packages, setPackages] = useState<PackageName[]>([]);
|
||||||
const [filters, setFilters] = useState<AuthLogFilters>(emptyFilters);
|
const [filters, setFilters] = useState<AuthLogFilters>(createDefaultFilters);
|
||||||
const [smsUnitCost, setSmsUnitCost] = useState<number>(DEFAULT_SMS_UNIT_COST);
|
const [smsUnitCost, setSmsUnitCost] = useState<number>(DEFAULT_SMS_UNIT_COST);
|
||||||
|
const [initialized, setInitialized] = useState(false);
|
||||||
const [stats, setStats] = useState<AuthStats | null>(null);
|
const [stats, setStats] = useState<AuthStats | null>(null);
|
||||||
const [logs, setLogs] = useState<PaginatedAuthLogs | null>(null);
|
const [logs, setLogs] = useState<PaginatedAuthLogs | null>(null);
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const [error, setError] = useState<string | null>(null);
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
// Restore the last SMS unit price the admin entered
|
|
||||||
useEffect(() => {
|
|
||||||
const saved = window.localStorage.getItem(SMS_COST_STORAGE_KEY);
|
|
||||||
if (saved) {
|
|
||||||
const parsed = parseInt(saved, 10);
|
|
||||||
if (!Number.isNaN(parsed) && parsed >= 0) setSmsUnitCost(parsed);
|
|
||||||
}
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const load = useCallback(async (
|
const load = useCallback(async (
|
||||||
targetPage: number,
|
targetPage: number,
|
||||||
activeFilters: AuthLogFilters,
|
activeFilters: AuthLogFilters,
|
||||||
@@ -95,10 +96,19 @@ export default function AuthAnalyticsPage() {
|
|||||||
packagesApi.getAllPackages(token).then(setPackages).catch(() => setPackages([]));
|
packagesApi.getAllPackages(token).then(setPackages).catch(() => setPackages([]));
|
||||||
}, [token]);
|
}, [token]);
|
||||||
|
|
||||||
|
// First load: restore the last SMS unit price the admin entered, then fetch
|
||||||
|
// today's activity with it (so the cost card is right on the very first render).
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!token) return;
|
if (!token || initialized) return;
|
||||||
load(1, emptyFilters, DEFAULT_SMS_UNIT_COST);
|
|
||||||
}, [token, load]);
|
const saved = window.localStorage.getItem(SMS_COST_STORAGE_KEY);
|
||||||
|
const parsed = saved ? parseInt(saved, 10) : NaN;
|
||||||
|
const unitCost = !Number.isNaN(parsed) && parsed >= 0 ? parsed : DEFAULT_SMS_UNIT_COST;
|
||||||
|
|
||||||
|
setSmsUnitCost(unitCost);
|
||||||
|
setInitialized(true);
|
||||||
|
load(1, createDefaultFilters(), unitCost);
|
||||||
|
}, [token, initialized, load]);
|
||||||
|
|
||||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
|
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
|
||||||
const { name, value } = e.target;
|
const { name, value } = e.target;
|
||||||
@@ -119,11 +129,12 @@ export default function AuthAnalyticsPage() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const handleReset = () => {
|
const handleReset = () => {
|
||||||
setFilters(emptyFilters);
|
const defaults = createDefaultFilters();
|
||||||
|
setFilters(defaults);
|
||||||
setSmsUnitCost(DEFAULT_SMS_UNIT_COST);
|
setSmsUnitCost(DEFAULT_SMS_UNIT_COST);
|
||||||
window.localStorage.setItem(SMS_COST_STORAGE_KEY, String(DEFAULT_SMS_UNIT_COST));
|
window.localStorage.setItem(SMS_COST_STORAGE_KEY, String(DEFAULT_SMS_UNIT_COST));
|
||||||
setPage(1);
|
setPage(1);
|
||||||
load(1, emptyFilters, DEFAULT_SMS_UNIT_COST);
|
load(1, defaults, DEFAULT_SMS_UNIT_COST);
|
||||||
};
|
};
|
||||||
|
|
||||||
const goToPage = (targetPage: number) => {
|
const goToPage = (targetPage: number) => {
|
||||||
@@ -277,7 +288,7 @@ export default function AuthAnalyticsPage() {
|
|||||||
value={smsUnitCost ? formatPrice(smsUnitCost) : ''}
|
value={smsUnitCost ? formatPrice(smsUnitCost) : ''}
|
||||||
onChange={handleUnitCostChange}
|
onChange={handleUnitCostChange}
|
||||||
className={inputClass}
|
className={inputClass}
|
||||||
placeholder="۸۰۰"
|
placeholder="۲۰۰۰"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user