home, subscription and other fixes

This commit is contained in:
Thomas Demirdjian
2025-11-06 17:33:07 +01:00
parent 5f777f3b6d
commit 4365f1e46d
31 changed files with 1579 additions and 348 deletions
+90 -3
View File
@@ -132,6 +132,62 @@ const capitalize = (value) => {
return value.charAt(0).toUpperCase() + value.slice(1);
};
const SCHEDULE_COMPARISON_HOUR = 2;
const SCHEDULE_COMPARISON_MINUTE = 30;
const SCHEDULE_DISPLAY_HOUR = 3;
const SCHEDULE_DISPLAY_MINUTE = 30;
const addMonthsSafe = (date, months = 1) => {
if (!(date instanceof Date) || !Number.isFinite(months)) {
return null;
}
const result = new Date(date.getTime());
const initialDay = result.getDate();
result.setMonth(result.getMonth() + months);
if (result.getDate() !== initialDay) {
result.setDate(0);
}
return result;
};
const addDaysSafe = (date, days = 1) => {
if (!(date instanceof Date) || !Number.isFinite(days)) {
return null;
}
const result = new Date(date.getTime());
result.setDate(result.getDate() + days);
return result;
};
const alignToScheduleTime = (date) => {
if (!(date instanceof Date)) {
return null;
}
const aligned = new Date(date.getTime());
aligned.setHours(SCHEDULE_DISPLAY_HOUR, SCHEDULE_DISPLAY_MINUTE, 0, 0);
return aligned;
};
const computeFirstAnnualGrantFromCreation = (creationDate) => {
if (!(creationDate instanceof Date)) {
return null;
}
const cutoff = new Date(creationDate.getTime());
cutoff.setHours(SCHEDULE_COMPARISON_HOUR, SCHEDULE_COMPARISON_MINUTE, 0, 0);
let base = null;
if (creationDate <= cutoff) {
base = addMonthsSafe(creationDate, 1);
} else {
base = addDaysSafe(creationDate, 1);
}
if (!base) {
return null;
}
return alignToScheduleTime(base);
};
const ManageSubscription = ({ navigation }) => {
const { currentUserData } = useUserData() || {};
const [isCancelling, setIsCancelling] = useState(false);
@@ -334,9 +390,40 @@ const ManageSubscription = ({ navigation }) => {
currentUserData?.subscriptionNextGrantAt ||
currentUserData?.subscriptionGrantNextAt ||
null;
const nextGrantDate = toDate(nextGrantTimestamp);
const nextGrantRawDate = toDate(nextGrantTimestamp);
const now = new Date();
const alignedStoredNextGrant = alignToScheduleTime(nextGrantRawDate);
const futureStoredNextGrant =
alignedStoredNextGrant &&
alignedStoredNextGrant.getTime() >= now.getTime()
? alignedStoredNextGrant
: null;
const fallbackInitialGrant =
isAnnual && createdAtDate
? computeFirstAnnualGrantFromCreation(createdAtDate)
: null;
const futureFallbackGrant =
fallbackInitialGrant &&
fallbackInitialGrant.getTime() >= now.getTime()
? fallbackInitialGrant
: null;
let resolvedNextGrantDate =
futureStoredNextGrant || futureFallbackGrant || null;
if (futureStoredNextGrant && futureFallbackGrant) {
resolvedNextGrantDate =
futureFallbackGrant.getTime() < futureStoredNextGrant.getTime()
? futureFallbackGrant
: futureStoredNextGrant;
}
const nextGrantLabel =
nextGrantDate && isAnnual ? formatDate(nextGrantDate) : null;
resolvedNextGrantDate && isAnnual
? formatDate(resolvedNextGrantDate)
: null;
const helperMessages = [];
if (!hasActiveSubscription && hasAnySubscription) {
@@ -374,7 +461,7 @@ const ManageSubscription = ({ navigation }) => {
coinsPerMonth: normalizedCoins,
coinsPerMonthLabel,
isAnnual,
nextGrantDate,
nextGrantDate: resolvedNextGrantDate,
nextGrantLabel,
};
}, [currentUserData, remoteSubscription]);