Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .rnstorybook/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { StorybookConfig } from '@storybook/react-native';
import type { StorybookConfig } from '@storybook/react-native';

const main: StorybookConfig = {
stories: ['../src/**/*.stories.?(ts|tsx|js|jsx)'],
Expand Down
6 changes: 4 additions & 2 deletions __mocks__/expo-image.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { View } from 'react-native';
import type { ImageProps } from 'expo-image';
import type { ViewProps } from 'react-native';

// Mock the Image component from expo-image
const Image = (props: any) => {
return <View {...props} />;
const Image = (props: ImageProps) => {
return <View {...(props as ViewProps)} />;
};

export { Image };
Expand Down
4 changes: 3 additions & 1 deletion __mocks__/react-native-mmkv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ const createMockStorage = () => {
return existed;
},
clearAll: () => {
Object.keys(data).forEach((key) => delete data[key]);
for (const key of Object.keys(data)) {
delete data[key];
}
},
};
};
Expand Down
5 changes: 1 addition & 4 deletions app.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
ios: {
supportsTablet: false,
bundleIdentifier: Env.BUNDLE_ID,
// TODO(prod): Add correct associated domain config
associatedDomains: ['applinks:rnstarter.onelink.me'],
// TODO(prod): Add correct app store URL
appStoreUrl: `https://apps.apple.com/app/XXX/${Env.ITUNES_ITEM_ID}`,
appStoreUrl: `https://apps.apple.com/app/${Env.ITUNES_ITEM_ID}`,
infoPlist: {
UIBackgroundModes: ['remote-notification'],
CFBundleAllowMixedLocalizations: true,
Expand Down
2 changes: 2 additions & 0 deletions src/domain/constants/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const androidVersionCode = Constants.expoConfig?.android?.versionCode
const runtimeVersion = Constants.expoConfig?.runtimeVersion;
const iosBundleIdentifier = Constants.expoConfig?.ios?.bundleIdentifier ?? '';
const androidPackageName = Constants.expoConfig?.android?.package ?? '';
const itunesItemId = Env.ITUNES_ITEM_ID;

const apiURL = Env.API_URL;
const isStorybookEnabled = Env.STORYBOOK_ENABLED === 'true';
Expand All @@ -36,6 +37,7 @@ export const config = {
buildNumber: IS_IOS ? iosbuildNumber : androidVersionCode,
runtimeVersion,
bundleId: IS_IOS ? iosBundleIdentifier : androidPackageName,
itunesItemId,
apiURL,
isStorybookEnabled,
// SDKs
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { PurchasesOffering } from 'react-native-purchases';
const SubscriptionContext = createContext<{
isPayingUser: boolean | null;
offeringToDisplay: PurchasesOffering | null;
handleSetIsPayingUser: (value: boolean) => void;
}>({
isPayingUser: null,
offeringToDisplay: null,
handleSetIsPayingUser: () => null,
});

export default SubscriptionContext;
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useMemo, useState } from 'react';
import { useCallback, useEffect, useMemo, useState } from 'react';
import { PurchasesOffering } from 'react-native-purchases';

import { hasActiveEntitlements } from '$domain/subscription';
Expand All @@ -7,6 +7,8 @@ import { Logger } from '$infra/logger';
import { Purchase } from '$infra/purchase';
import { useRunOnMount } from '$shared/hooks';

import { useAuthContext } from '../authContext';

import SubscriptionContext from './SubscriptionContext';

interface SubscriptionContextProviderProps {
Expand All @@ -20,11 +22,20 @@ export const SubscriptionContextProvider = ({
const [offeringToDisplay, setOfferingToDisplay] =
useState<PurchasesOffering | null>(null);

const { user } = useAuthContext();

const { getFlagPayloadSync } = useGetRemoteConfigSync();

useRunOnMount(() => {
useEffect(() => {
const fetchIsPayingUser = async () => {
if (!user) {
setIsPayingUser(false);

return;
}

try {
await Purchase.setUser(user);
const isPayingUser = await Purchase.isPayingUser();

setIsPayingUser(isPayingUser);
Expand All @@ -40,7 +51,7 @@ export const SubscriptionContextProvider = ({
};

void fetchIsPayingUser();
});
}, [user]);

useRunOnMount(() => {
return Purchase.customerListener((customerInfo) => {
Expand Down Expand Up @@ -81,12 +92,17 @@ export const SubscriptionContextProvider = ({
void fetchOfferingToDisplay();
});

const handleSetIsPayingUser = useCallback((value: boolean) => {
setIsPayingUser(value);
}, []);

const value = useMemo(
() => ({
isPayingUser,
offeringToDisplay,
handleSetIsPayingUser,
}),
[isPayingUser, offeringToDisplay],
[isPayingUser, offeringToDisplay, handleSetIsPayingUser],
);

return (
Expand Down
1 change: 0 additions & 1 deletion src/infra/analytics/analytics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ class AnalyticsClass {
}
/* ***** ***** User related ***** ***** */

// TODO(prod): Add user properties
setUser(user: User) {
productTrackingClient.identify(user.id, {
email: user.email,
Expand Down
4 changes: 2 additions & 2 deletions src/infra/date/date.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import dayjsLocalizedFormat from 'dayjs/plugin/localizedFormat';
import relativeTime from 'dayjs/plugin/relativeTime';
import dayjsUtc from 'dayjs/plugin/utc';

import type { DateFormats } from './date.types';
import type { DateFormat } from './date.types';

import 'dayjs/locale/fr';
import 'dayjs/locale/en';
Expand All @@ -25,7 +25,7 @@ export const formatDate = ({
format,
}: {
date: dayjs.ConfigType;
format: DateFormats;
format: DateFormat;
}) => dayjs.utc(date).format(format);

export const formatDateRelative = ({
Expand Down
44 changes: 22 additions & 22 deletions src/infra/date/date.types.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
export enum DateFormats {
/** 8:02 PM */
TIME = 'LT',
/** 08/16/2018 */
SHORT_DATE = 'L',
/** Aug 16, 2018 */
MEDIUM_DATE = 'll',
/** August 16, 2018 */
LONG_DATE = 'LL',
/** August 16, 2018 8:02 PM */
LONG_DATE_WITH_TIME = 'LLL',
/** Sunday-Saturday */
DAY = 'dddd',
/** January-December */
MONTH = 'MMMM',
/** 16 Aout 2018 */
DATE_FR = 'DD MMMM YYYY',
/** August 16, 2018 */
DATE_EN = 'MMM Do, YYYY',
/** August 2018 */
DATE_WITHOUT_DAY = 'MMMM YYYY',
}
export const DateFormats = {
/** 3:30 PM (US) | 15:30 (FR) */
TIME: 'LT',
/** 01/11/2026 (US) | 11/01/2026 (FR) */
SHORT_DATE: 'L',
/** Jan 11, 2026 (US) | 11 janv. 2026 (FR) */
MEDIUM_DATE: 'll',
/** January 11, 2026 (US) | 11 janvier 2026 (FR) */
LONG_DATE: 'LL',
/** January 11, 2026 3:30 PM (US) | 11 janvier 2026 15:30 (FR) */
LONG_DATE_WITH_TIME: 'LLL',
/** 1/11/26 - 3:30 PM (US) | 11/1/26 - 15:30 (FR) */
SHORT_DATE_WITH_TIME: 'l - LT',
/** Sunday (US) | dimanche (FR) */
DAY: 'dddd',
/** January (US) | janvier (FR) */
MONTH: 'MMMM',
/** January 2026 (US) | janvier 2026 (FR) */
MONTH_YEAR: 'MMMM YYYY',
} as const;

export type DateFormat = (typeof DateFormats)[keyof typeof DateFormats];
4 changes: 2 additions & 2 deletions src/infra/date/hooks/useDates.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ import { useMemo } from 'react';
import { useTranslation } from 'react-i18next';

import { formatDate, formatDateRelative } from '../date';
import { DateFormats } from '../date.types';
import { DateFormat } from '../date.types';

export const useFormatDate = ({
date,
format,
}: {
date: dayjs.ConfigType;
format: DateFormats;
format: DateFormat;
}): string => {
const { i18n } = useTranslation();

Expand Down
2 changes: 1 addition & 1 deletion src/infra/logger/logger.types.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { SeverityLevel } from '@sentry/core';
import type { SeverityLevel } from '@sentry/react-native';

/* ***** ***** Toast Message ***** ***** */

Expand Down
10 changes: 5 additions & 5 deletions src/infra/monitoring/errorMonitoring.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
/* eslint-disable @typescript-eslint/no-deprecated */

import type { Event, Scope } from '@sentry/react-native';
import * as Sentry from '@sentry/react-native';
import type { Breadcrumb, CaptureContext, SeverityLevel } from '@sentry/types';
import * as Application from 'expo-application';
import Constants from 'expo-constants';
import * as Device from 'expo-device';
Expand Down Expand Up @@ -107,7 +104,10 @@ class ErrorMonitoringClass {
Sentry.captureException(exception);
}

message(message: string, context?: CaptureContext | SeverityLevel) {
message(
message: string,
context?: Parameters<typeof Sentry.captureMessage>[1],
) {
Sentry.captureMessage(message, context);
}

Expand All @@ -119,7 +119,7 @@ class ErrorMonitoringClass {
Sentry.setContext(name, context);
}

breadcrumbs(breadcrumb: Breadcrumb) {
breadcrumbs(breadcrumb: Sentry.Breadcrumb) {
Sentry.addBreadcrumb(breadcrumb);
}

Expand Down
15 changes: 7 additions & 8 deletions src/infra/monitoring/performanceMonitoring.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,17 @@
/* eslint-disable @typescript-eslint/no-deprecated */

import * as Sentry from '@sentry/react-native';
import type { StartSpanOptions, Span } from '@sentry/types';

class PerformanceMonitoringClass {
startTransaction<T>(
context: StartSpanOptions,
callback: (span: Span | undefined) => T,
context: Parameters<typeof Sentry.startSpan>[0],
callback: (span: Sentry.Span | undefined) => T,
) {
Sentry.startSpan(context, callback);
return Sentry.startSpan(context, callback);
}
Comment thread
tsyirvo marked this conversation as resolved.

startIndependentTransaction(context: StartSpanOptions) {
Sentry.startInactiveSpan(context);
startIndependentTransaction(
context: Parameters<typeof Sentry.startInactiveSpan>[0],
) {
return Sentry.startInactiveSpan(context);
}
Comment thread
tsyirvo marked this conversation as resolved.
}

Expand Down
4 changes: 4 additions & 0 deletions src/infra/purchase/purchase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ class PurchaseClass {
await RevenueCat.restorePurchases();
}

async syncPurchases() {
await RevenueCat.syncPurchases();
}

async makePurchase(purchasedPackage: PurchasesPackage) {
try {
await RevenueCat.purchasePackage(purchasedPackage);
Expand Down
2 changes: 1 addition & 1 deletion src/infra/storage/productTrackingStorage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createMMKV } from 'react-native-mmkv';

import { storageKeys } from '$domain/constants';

export const ProductTrackingStorage = createMMKV({
const ProductTrackingStorage = createMMKV({
id: storageKeys.productTrackingStorage.id,
});

Expand Down
5 changes: 1 addition & 4 deletions src/shared/components/appUpdateNeeded/AppUpdateNeeded.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,9 @@ export const AppUpdateNeeded = () => {

const onPress = async () => {
try {
// TODO(prod): Replace with real iTunes item ID
const itunesItemId = '';

await Linking.openURL(
IS_IOS
? `https://apps.apple.com/app/apple-store/id${itunesItemId}`
? `https://apps.apple.com/app/${config.itunesItemId}`
: `market://details?id=${config.bundleId}&showAllReviews=true`,
);
} catch (error) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,9 @@ export const StoreUpdateAvailableBanner = () => {

const onPress = async () => {
try {
// TODO(prod): Replace with real iTunes item ID
const itunesItemId = '';

await Linking.openURL(
IS_IOS
? `https://apps.apple.com/app/apple-store/id${itunesItemId}`
? `https://apps.apple.com/app/${config.itunesItemId}`
: `market://details?id=${config.bundleId}&showAllReviews=true`,
);
} catch (error) {
Expand Down
2 changes: 1 addition & 1 deletion src/shared/hooks/useAppState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,5 @@ export const useAppState = ({
return () => {
listener.remove();
};
}, [appState, handleAppStateChange]);
}, [handleAppStateChange]);
};