Polish mobile app for App Store review and expand CRUD.
Default to beenvoice.soconnor.dev with server settings hidden behind Advanced; add Entities tab with clients/businesses, invoice creation, UI fixes for dashboard layout, date fields, FAB position, and card-matched button radius. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+4
-3
@@ -1,6 +1,7 @@
|
||||
import Constants from "expo-constants";
|
||||
|
||||
const fallbackUrl = "http://localhost:3000";
|
||||
/** Production API used by default (App Store review + production builds). */
|
||||
export const DEFAULT_API_URL = "https://beenvoice.soconnor.dev";
|
||||
|
||||
let runtimeOverride: string | null = null;
|
||||
|
||||
@@ -15,10 +16,10 @@ export function getApiUrl() {
|
||||
if (fromEnv) return fromEnv.replace(/\/$/, "");
|
||||
|
||||
const hostUri = Constants.expoConfig?.hostUri;
|
||||
if (hostUri) {
|
||||
if (hostUri && __DEV__) {
|
||||
const host = hostUri.split(":")[0];
|
||||
if (host) return `http://${host}:3000`;
|
||||
}
|
||||
|
||||
return fallbackUrl;
|
||||
return DEFAULT_API_URL;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/** Matches web invoice-form default numbering. */
|
||||
export function generateInvoiceNumber(): string {
|
||||
const date = new Date().toISOString().slice(0, 10).replace(/-/g, "");
|
||||
return `INV-${date}-${String(Date.now()).slice(-6)}`;
|
||||
}
|
||||
|
||||
export function defaultDueDate(issueDate: Date): Date {
|
||||
const due = new Date(issueDate);
|
||||
due.setDate(due.getDate() + 30);
|
||||
return due;
|
||||
}
|
||||
+14
-8
@@ -6,8 +6,8 @@ import { spacing } from "@/constants/theme";
|
||||
/** Standard UITabBar content height (home indicator is separate). */
|
||||
const IOS_TAB_BAR_HEIGHT = 49;
|
||||
|
||||
/** Slightly less than measured inset so content sits closer to the tab bar. */
|
||||
const TAB_BAR_PADDING_TRIM = spacing.sm;
|
||||
/** Trim extra inset so scroll content sits closer to the tab bar. */
|
||||
const TAB_BAR_PADDING_TRIM = spacing.lg;
|
||||
|
||||
/**
|
||||
* Pixels between the bottom of the safe-area layout frame and the window bottom.
|
||||
@@ -31,17 +31,23 @@ export function useNativeTabBarHeight(): number {
|
||||
|
||||
/**
|
||||
* Bottom padding so scroll content can clear the floating native tab bar.
|
||||
* Uses layout-frame measurement when available, otherwise tab bar + home indicator.
|
||||
* Uses tab bar + home indicator as the target — layout-frame measurement can
|
||||
* over-report and leave a large empty scroll gap above the tab bar.
|
||||
*/
|
||||
export function useTabBarScrollPadding(): number {
|
||||
const belowLayoutFrame = useBelowLayoutFrame();
|
||||
const { bottom: homeIndicator } = useSafeAreaInsets();
|
||||
const tabBar = useNativeTabBarHeight();
|
||||
const clearance = tabBar + homeIndicator;
|
||||
|
||||
return Math.max(spacing.xs, clearance - TAB_BAR_PADDING_TRIM);
|
||||
}
|
||||
|
||||
/** Bottom offset for floating action buttons above the tab bar. */
|
||||
export function useFloatingActionBottom(): number {
|
||||
const { bottom: homeIndicator } = useSafeAreaInsets();
|
||||
const tabBar = useNativeTabBarHeight();
|
||||
|
||||
const raw =
|
||||
belowLayoutFrame > 0 ? belowLayoutFrame : tabBar + homeIndicator;
|
||||
|
||||
return Math.max(tabBar + homeIndicator - TAB_BAR_PADDING_TRIM, raw - TAB_BAR_PADDING_TRIM);
|
||||
return tabBar + homeIndicator + spacing.xs;
|
||||
}
|
||||
|
||||
/** @deprecated Use useTabBarScrollPadding */
|
||||
|
||||
@@ -51,6 +51,10 @@ export type ThemeColors = {
|
||||
brandDark: string;
|
||||
text: string;
|
||||
textMuted: string;
|
||||
switchTrackOn: string;
|
||||
switchTrackOff: string;
|
||||
switchThumb: string;
|
||||
switchIosBackground: string;
|
||||
};
|
||||
|
||||
export function getThemeColors(scheme: ColorSchemeName): ThemeColors {
|
||||
@@ -83,6 +87,10 @@ export function getThemeColors(scheme: ColorSchemeName): ThemeColors {
|
||||
brandDark: palette?.foreground ?? light.foreground,
|
||||
text: palette?.foreground ?? light.foreground,
|
||||
textMuted: palette?.mutedForeground ?? light.mutedForeground,
|
||||
switchTrackOn: isDark ? (palette?.success ?? "#4ADE80") : light.primary,
|
||||
switchTrackOff: isDark ? "#3F3F46" : light.border,
|
||||
switchThumb: isDark ? "#FAFAFA" : "#FFFFFF",
|
||||
switchIosBackground: isDark ? "#3F3F46" : light.border,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user