Update icons, screenshots, and UX improvements

- Refactor icon picker to use full Ionicons set dynamically
- Add date sort toggle to My Answers screen
- Fix match deduplication and show total count on home
- Clear stale data when switching chats
- Update app store screenshots
- Bump build number to 25

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
jjbruntonandClaude Opus 4.5 committed 2026-01-08 19:58:29 +00:00
1 parent c48936686e
commit b60b72a289
64 files changed
+381 -298

No files matched your search

+4 -5
View File
@@ -30,11 +30,10 @@
"emoji-mart": "^5.6.0",
"lucide-react": "^0.309.0",
"openai": "^4.24.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.12.0",
"react-router-dom": "^6.21.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.12.0",
"react-router-dom": "^6.21.0",
"recharts": "^3.6.0",
"sonner": "^1.3.1",
"tailwind-merge": "^2.2.0"
+25 -106
View File
@@ -1,48 +1,6 @@
import { useEffect, useMemo, useRef, useState } from 'react';
import type { IconType } from 'react-icons';
import {
IoHeartOutline,
IoHeartHalfOutline,
IoHeartCircleOutline,
IoChatbubblesOutline,
IoChatboxOutline,
IoMailOutline,
IoFlowerOutline,
IoWineOutline,
IoRestaurantOutline,
IoCafeOutline,
IoAirplaneOutline,
IoCarOutline,
IoCompassOutline,
IoMapOutline,
IoHomeOutline,
IoPeopleOutline,
IoPersonOutline,
IoEyeOffOutline,
IoKeyOutline,
IoLockClosedOutline,
IoDiceOutline,
IoGiftOutline,
IoSparklesOutline,
IoStarOutline,
IoFlameOutline,
IoFlashOutline,
IoMoonOutline,
IoSunnyOutline,
IoFlagOutline,
IoCalendarOutline,
IoCheckboxOutline,
IoTrophyOutline,
IoLayersOutline,
IoCubeOutline,
IoFolderOutline,
IoBookmarkOutline,
IoBulbOutline,
IoColorWandOutline,
IoSyncOutline,
IoRefreshOutline,
IoBriefcaseOutline,
} from 'react-icons/io5';
import * as Io5Icons from 'react-icons/io5';
import { Button } from './button';
import { Input } from './input';
@@ -51,68 +9,28 @@ interface IconOption {
Icon: IconType;
}
const ICON_OPTIONS: IconOption[] = [
// Relationships & Love
{ name: 'heart-outline', Icon: IoHeartOutline },
{ name: 'heart-half-outline', Icon: IoHeartHalfOutline },
{ name: 'heart-circle-outline', Icon: IoHeartCircleOutline },
/**
* Convert PascalCase component name to kebab-case Ionicon name.
* e.g., "IoHeartOutline" -> "heart-outline"
*/
function toKebabCase(componentName: string): string {
// Remove "Io" prefix
const withoutPrefix = componentName.slice(2);
// Convert PascalCase to kebab-case
return withoutPrefix
.replace(/([a-z])([A-Z])/g, '$1-$2')
.replace(/([A-Z])([A-Z][a-z])/g, '$1-$2')
.toLowerCase();
}
// Communication
{ name: 'chatbubbles-outline', Icon: IoChatbubblesOutline },
{ name: 'chatbox-outline', Icon: IoChatboxOutline },
{ name: 'mail-outline', Icon: IoMailOutline },
// Romance & Dates
{ name: 'flower-outline', Icon: IoFlowerOutline },
{ name: 'wine-outline', Icon: IoWineOutline },
{ name: 'restaurant-outline', Icon: IoRestaurantOutline },
{ name: 'cafe-outline', Icon: IoCafeOutline },
// Adventure & Travel
{ name: 'airplane-outline', Icon: IoAirplaneOutline },
{ name: 'car-outline', Icon: IoCarOutline },
{ name: 'compass-outline', Icon: IoCompassOutline },
{ name: 'map-outline', Icon: IoMapOutline },
// Home & Family
{ name: 'home-outline', Icon: IoHomeOutline },
{ name: 'people-outline', Icon: IoPeopleOutline },
{ name: 'person-outline', Icon: IoPersonOutline },
// Mystery & Secrets
{ name: 'eye-off-outline', Icon: IoEyeOffOutline },
{ name: 'key-outline', Icon: IoKeyOutline },
{ name: 'lock-closed-outline', Icon: IoLockClosedOutline },
// Fun & Games
{ name: 'dice-outline', Icon: IoDiceOutline },
{ name: 'gift-outline', Icon: IoGiftOutline },
{ name: 'sparkles-outline', Icon: IoSparklesOutline },
{ name: 'star-outline', Icon: IoStarOutline },
// Intimacy
{ name: 'flame-outline', Icon: IoFlameOutline },
{ name: 'flash-outline', Icon: IoFlashOutline },
{ name: 'moon-outline', Icon: IoMoonOutline },
{ name: 'sunny-outline', Icon: IoSunnyOutline },
// Goals & Planning
{ name: 'flag-outline', Icon: IoFlagOutline },
{ name: 'calendar-outline', Icon: IoCalendarOutline },
{ name: 'checkbox-outline', Icon: IoCheckboxOutline },
{ name: 'trophy-outline', Icon: IoTrophyOutline },
// General
{ name: 'layers-outline', Icon: IoLayersOutline },
{ name: 'cube-outline', Icon: IoCubeOutline },
{ name: 'folder-outline', Icon: IoFolderOutline },
{ name: 'bookmark-outline', Icon: IoBookmarkOutline },
{ name: 'bulb-outline', Icon: IoBulbOutline },
{ name: 'color-wand-outline', Icon: IoColorWandOutline },
{ name: 'sync-outline', Icon: IoSyncOutline },
{ name: 'refresh-outline', Icon: IoRefreshOutline },
{ name: 'briefcase-outline', Icon: IoBriefcaseOutline },
];
// Build icon options from all Io5 icons dynamically
const ICON_OPTIONS: IconOption[] = Object.entries(Io5Icons)
.filter(([name]) => name.startsWith('Io'))
.map(([componentName, Icon]) => ({
name: toKebabCase(componentName),
Icon: Icon as IconType,
}))
.sort((a, b) => a.name.localeCompare(b.name));
const ICONS_BY_NAME = ICON_OPTIONS.reduce<Record<string, IconOption>>((acc, option) => {
acc[option.name] = option;
@@ -168,8 +86,9 @@ export function IconPicker({ value, onChange }: IconPickerProps) {
return ICON_OPTIONS.filter((option) => option.name.includes(normalized));
}, [query]);
const SelectedIcon = ICONS_BY_NAME[value]?.Icon;
const buttonLabel = SelectedIcon ? value : value ? 'Legacy icon' : 'Select an icon';
const selectedOption = ICONS_BY_NAME[value];
const SelectedIcon = selectedOption?.Icon;
const buttonLabel = selectedOption ? value : value ? 'Legacy icon' : 'Select an icon';
return (
<div className="relative" ref={containerRef}>
+1 -1
View File
@@ -16,7 +16,7 @@
"ios": {
"supportsTablet": false,
"bundleIdentifier": "com.sauci.app",
"buildNumber": "24",
"buildNumber": "25",
"usesAppleSignIn": true,
"infoPlist": {
"UIBackgroundModes": [
+2 -2
View File
@@ -22,7 +22,7 @@ const ACCENT_COLOR = colors.primary;
export default function HomeScreen() {
const { user, partner, couple } = useAuthStore();
const { matches, newMatchesCount, fetchMatches } = useMatchStore();
const { matches, newMatchesCount, totalCount, fetchMatches } = useMatchStore();
const { enabledPackIds, fetchPacks } = usePacksStore();
const { width } = useWindowDimensions();
@@ -146,7 +146,7 @@ export default function HomeScreen() {
color={matches.length > 0 ? colors.text : ACCENT_COLOR}
/>
</View>
<Text style={styles.statNumber}>{matches.length}</Text>
<Text style={styles.statNumber}>{totalCount ?? matches.length}</Text>
<Text style={styles.statLabel}>Matches</Text>
</View>
</TouchableOpacity>
+40 -12
View File
@@ -47,7 +47,7 @@ const AnimatedSectionList = Animated.createAnimatedComponent(SectionList);
type GroupByOption = "pack" | "date" | "answer";
export default function MyAnswersScreen() {
const { responses, isLoading, isLoadingMore, hasMore, groupBy, fetchResponses, setGroupBy, totalCount } = useResponsesStore();
const { responses, isLoading, isLoadingMore, hasMore, groupBy, dateSortOrder, fetchResponses, setGroupBy, toggleDateSortOrder, totalCount } = useResponsesStore();
const { user } = useAuthStore();
const router = useRouter();
const params = useLocalSearchParams();
@@ -123,7 +123,7 @@ export default function MyAnswersScreen() {
}
}, [isLoading, isLoadingMore, hasMore]);
const sections = groupResponses(responses, groupBy);
const sections = groupResponses(responses, groupBy, dateSortOrder);
const handleEditPress = (response: ResponseWithQuestion) => {
setSelectedResponse(response);
@@ -164,16 +164,39 @@ export default function MyAnswersScreen() {
);
};
const GroupByButton = ({ option, label }: { option: GroupByOption; label: string }) => (
<TouchableOpacity
style={[styles.groupByButton, groupBy === option && styles.groupByButtonActive]}
onPress={() => setGroupBy(option)}
>
<Text style={[styles.groupByText, groupBy === option && styles.groupByTextActive]}>
{label}
</Text>
</TouchableOpacity>
);
const GroupByButton = ({ option, label }: { option: GroupByOption; label: string }) => {
const isActive = groupBy === option;
const isDateButton = option === "date";
const showChevron = isDateButton && isActive;
const handlePress = () => {
if (isDateButton && isActive) {
// Toggle sort order when date is already selected
toggleDateSortOrder();
} else {
setGroupBy(option);
}
};
return (
<TouchableOpacity
style={[styles.groupByButton, isActive && styles.groupByButtonActive]}
onPress={handlePress}
>
<Text style={[styles.groupByText, isActive && styles.groupByTextActive]}>
{label}
</Text>
{showChevron && (
<Ionicons
name={dateSortOrder === "newest" ? "chevron-down" : "chevron-up"}
size={14}
color={ACCENT}
style={styles.sortChevron}
/>
)}
</TouchableOpacity>
);
};
if (!user) {
return (
@@ -441,6 +464,8 @@ const styles = StyleSheet.create({
marginTop: spacing.md,
},
groupByButton: {
flexDirection: "row",
alignItems: "center",
paddingHorizontal: spacing.md,
paddingVertical: spacing.sm,
borderRadius: radius.full,
@@ -461,6 +486,9 @@ const styles = StyleSheet.create({
color: ACCENT,
fontWeight: "600",
},
sortChevron: {
marginLeft: spacing.xs,
},
// Section header
sectionHeader: {
paddingVertical: spacing.sm,
+3 -3
View File
@@ -47,7 +47,7 @@
</dict>
</array>
<key>CFBundleVersion</key>
<string>20</string>
<string>25</string>
<key>LSMinimumSystemVersion</key>
<string>12.0</string>
<key>LSRequiresIPhoneOS</key>
@@ -60,7 +60,7 @@
<true/>
</dict>
<key>NSCameraUsageDescription</key>
<string>Sauci uses your camera to take photos and videos that you can share privately with your partner in encrypted chat messages.</string>
<string>Sauci uses your camera to take photos and videos that you can share privately with your partner.</string>
<key>NSFaceIDUsageDescription</key>
<string>Sauci uses Face ID to unlock the app and keep your conversations private.</string>
<key>NSMicrophoneUsageDescription</key>
@@ -68,7 +68,7 @@
<key>NSPhotoLibraryAddUsageDescription</key>
<string>Sauci saves photos and videos from your partner's messages to your photo library when you tap the save button.</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Sauci uses your photo library so you can select photos and videos to share privately with your partner in encrypted chat messages.</string>
<string>Sauci uses your photo library so you can select photos and videos to share privately with your partner.</string>
<key>NSUserActivityTypes</key>
<array>
<string>$(PRODUCT_BUNDLE_IDENTIFIER).expo.index_route</string>
@@ -149,6 +149,7 @@ export const ChatScreen: React.FC = () => {
if (!matchId) return;
const fetchMatch = async () => {
setMatch(null); // Clear previous match data immediately
const { data } = await supabase
.from("matches")
.select("*, question:questions(*)")
@@ -104,6 +104,7 @@ export const useMessageSubscription = (
const fetchMessagesAndMarkRead = async () => {
setLoading(true);
setAllMessages([]); // Clear previous chat's messages immediately
const { data } = await supabase
.from('messages')
+14 -49
View File
@@ -1,7 +1,15 @@
import type { Ionicons } from "@expo/vector-icons";
import { Ionicons } from "@expo/vector-icons";
type IoniconsName = keyof typeof Ionicons.glyphMap;
/**
* Checks if a string is a valid Ionicons name.
* Uses the actual Ionicons.glyphMap for runtime validation.
*/
function isValidIonicon(name: string): name is IoniconsName {
return name in Ionicons.glyphMap;
}
// Legacy emoji mappings (for backwards compatibility with existing packs)
const EMOJI_TO_IONICON: Record<string, IoniconsName> = {
// Career & Professional
@@ -49,63 +57,20 @@ export const PACK_ICON_MAP = EMOJI_TO_IONICON;
export const DEFAULT_PACK_ICON: IoniconsName = "layers-outline";
// List of valid Ionicon names (subset we support)
const VALID_IONICONS = new Set([
"heart-outline",
"heart-half-outline",
"heart-circle-outline",
"chatbubbles-outline",
"chatbox-outline",
"mail-outline",
"flower-outline",
"wine-outline",
"restaurant-outline",
"cafe-outline",
"airplane-outline",
"car-outline",
"compass-outline",
"map-outline",
"home-outline",
"people-outline",
"person-outline",
"eye-off-outline",
"key-outline",
"lock-closed-outline",
"dice-outline",
"gift-outline",
"sparkles-outline",
"star-outline",
"flame-outline",
"flash-outline",
"moon-outline",
"sunny-outline",
"flag-outline",
"calendar-outline",
"checkbox-outline",
"trophy-outline",
"layers-outline",
"cube-outline",
"folder-outline",
"bookmark-outline",
"bulb-outline",
"color-wand-outline",
"sync-outline",
"refresh-outline",
"briefcase-outline",
]);
/**
* Converts an icon value to an Ionicons name.
* Handles both:
* - Ionicon names directly (new packs): "briefcase-outline" -> "briefcase-outline"
* - Any valid Ionicon name directly: "briefcase-outline" -> "briefcase-outline"
* - Legacy emojis (existing packs): "💼" -> "briefcase-outline"
*/
export function getPackIconName(icon: string | null | undefined): IoniconsName {
if (!icon) return DEFAULT_PACK_ICON;
if (VALID_IONICONS.has(icon)) {
return icon as IoniconsName;
// Check if it's a valid Ionicon name (supports the full Ionicons set)
if (isValidIonicon(icon)) {
return icon;
}
// Fall back to emoji mapping for legacy packs
return EMOJI_TO_IONICON[icon] || DEFAULT_PACK_ICON;
}
+1 -1
View File
@@ -5,4 +5,4 @@ export { usePacksStore } from "./packsStore";
export { useMessageStore } from "./messageStore";
export { useSubscriptionStore } from "./subscriptionStore";
export { useResponsesStore, groupResponses } from "./responsesStore";
export type { ResponseWithQuestion, UpdateResponseResult, GroupByOption } from "./responsesStore";
export type { ResponseWithQuestion, UpdateResponseResult, GroupByOption, DateSortOrder } from "./responsesStore";
+15 -3
View File
@@ -147,15 +147,27 @@ export const useMatchStore = create<MatchState>((set, get) => ({
// Ideally we should have a separate query for count, but we'll just count in current batch
const newMatchesInBatch = sortedData.filter((m) => m.is_new).length;
set((state) => ({
matches: refresh ? sortedData : [...state.matches, ...sortedData],
set((state) => {
// Deduplicate matches by ID when appending new pages
const mergedMatches = refresh
? sortedData
: [...state.matches, ...sortedData].reduce<Match[]>((acc, match) => {
if (!acc.some((m: Match) => m.id === match.id)) {
acc.push(match);
}
return acc;
}, []);
return {
matches: mergedMatches,
newMatchesCount: refresh ? newMatchesInBatch : state.newMatchesCount + newMatchesInBatch,
totalCount: refresh ? totalCount : state.totalCount,
isLoading: false,
isLoadingMore: false,
page: currentPage + 1,
hasMore: matches.length === BATCH_SIZE
}));
};
});
} catch (err) {
console.error("Error fetching matches:", err);
set({ error: "Failed to load matches", isLoading: false, isLoadingMore: false });
+28 -5
View File
@@ -32,6 +32,7 @@ export interface UpdateResponseResult {
}
export type GroupByOption = "pack" | "date" | "answer";
export type DateSortOrder = "newest" | "oldest";
const BATCH_SIZE = 20;
@@ -40,6 +41,7 @@ interface ResponsesState {
isLoading: boolean;
isLoadingMore: boolean;
groupBy: GroupByOption;
dateSortOrder: DateSortOrder;
hasMore: boolean;
page: number;
totalCount: number | null;
@@ -50,6 +52,8 @@ interface ResponsesState {
confirmDelete?: boolean
) => Promise<UpdateResponseResult>;
setGroupBy: (groupBy: GroupByOption) => void;
setDateSortOrder: (order: DateSortOrder) => void;
toggleDateSortOrder: () => void;
clearResponses: () => void;
}
@@ -57,7 +61,8 @@ export const useResponsesStore = create<ResponsesState>((set, get) => ({
responses: [],
isLoading: false,
isLoadingMore: false,
groupBy: "pack",
groupBy: "date",
dateSortOrder: "newest",
hasMore: true,
page: 0,
totalCount: null,
@@ -270,15 +275,26 @@ export const useResponsesStore = create<ResponsesState>((set, get) => ({
set({ groupBy });
},
clearResponses: () => {
set({ responses: [], isLoading: false, groupBy: "pack", page: 0, hasMore: true, isLoadingMore: false, totalCount: null });
setDateSortOrder: (order: DateSortOrder) => {
set({ dateSortOrder: order });
},
toggleDateSortOrder: () => {
set((state) => ({
dateSortOrder: state.dateSortOrder === "newest" ? "oldest" : "newest",
}));
},
clearResponses: () => {
set({ responses: [], isLoading: false, groupBy: "date", dateSortOrder: "newest", page: 0, hasMore: true, isLoadingMore: false, totalCount: null });
},
}));
// Helper function to group responses
export function groupResponses(
responses: ResponseWithQuestion[],
groupBy: GroupByOption
groupBy: GroupByOption,
dateSortOrder: DateSortOrder = "newest"
): { title: string; data: ResponseWithQuestion[] }[] {
if (groupBy === "pack") {
// Group by pack name
@@ -307,9 +323,16 @@ export function groupResponses(
}
if (groupBy === "date") {
// Sort responses by date based on sort order
const sortedResponses = [...responses].sort((a, b) => {
const dateA = new Date(a.created_at).getTime();
const dateB = new Date(b.created_at).getTime();
return dateSortOrder === "newest" ? dateB - dateA : dateA - dateB;
});
// Group by date (day)
const groups = new Map<string, ResponseWithQuestion[]>();
responses.forEach((r) => {
sortedResponses.forEach((r) => {
const date = new Date(r.created_at).toLocaleDateString("en-US", {
year: "numeric",
month: "long",
@@ -0,0 +1,173 @@
-- Filter individual questions by user's max_intensity preference
-- This fixes a bug where users would see intense questions despite having a gentle comfort zone
CREATE OR REPLACE FUNCTION get_recommended_questions(target_pack_id UUID DEFAULT NULL)
RETURNS TABLE(
id UUID,
text TEXT,
partner_text TEXT,
is_two_part BOOLEAN,
pack_id UUID,
intensity INTEGER,
partner_answered BOOLEAN,
allowed_couple_genders TEXT[],
target_user_genders TEXT[]
)
LANGUAGE plpgsql
SECURITY DEFINER
SET search_path = 'public'
AS $$
DECLARE
v_user_id UUID;
v_couple_id UUID;
v_partner_id UUID;
v_user_gender TEXT;
v_partner_gender TEXT;
v_couple_type TEXT;
v_has_premium BOOLEAN;
v_gap_threshold INTEGER;
v_gap_count INTEGER;
v_user_max_intensity INTEGER;
BEGIN
v_user_id := auth.uid();
SELECT p.couple_id, p.gender, COALESCE(p.max_intensity, 5)
INTO v_couple_id, v_user_gender, v_user_max_intensity
FROM public.profiles p
WHERE p.id = v_user_id;
IF v_couple_id IS NULL THEN
RETURN;
END IF;
SELECT p.id, p.gender INTO v_partner_id, v_partner_gender
FROM public.profiles p
WHERE p.couple_id = v_couple_id AND p.id != v_user_id
LIMIT 1;
-- Check answer gap threshold (only when not browsing a specific pack)
IF v_partner_id IS NOT NULL AND target_pack_id IS NULL THEN
-- Get threshold from app_config
SELECT COALESCE(ac.answer_gap_threshold, 10) INTO v_gap_threshold
FROM app_config ac
LIMIT 1;
-- If threshold > 0, check the gap
IF v_gap_threshold > 0 THEN
-- Count questions in ENABLED packs where user answered but partner hasn't
WITH enabled_packs AS (
SELECT cp.pack_id
FROM couple_packs cp
WHERE cp.couple_id = v_couple_id AND cp.enabled = true
)
SELECT COUNT(*)::integer INTO v_gap_count
FROM responses r
INNER JOIN questions q ON q.id = r.question_id
WHERE r.user_id = v_user_id
AND r.couple_id = v_couple_id
AND EXISTS (SELECT 1 FROM enabled_packs)
AND q.pack_id IN (SELECT ep.pack_id FROM enabled_packs ep)
AND NOT EXISTS (
SELECT 1 FROM responses pr
WHERE pr.question_id = r.question_id
AND pr.user_id = v_partner_id
);
-- If over threshold, return empty (old apps see "All caught up!")
IF v_gap_count >= v_gap_threshold THEN
RETURN;
END IF;
END IF;
END IF;
IF v_user_gender IS NOT NULL AND v_partner_gender IS NOT NULL THEN
IF v_user_gender < v_partner_gender THEN
v_couple_type := v_user_gender || '+' || v_partner_gender;
ELSE
v_couple_type := v_partner_gender || '+' || v_user_gender;
END IF;
END IF;
v_has_premium := public.has_premium_access(v_user_id);
RETURN QUERY
WITH user_config_exists AS (
SELECT 1 FROM public.couple_packs WHERE couple_id = v_couple_id LIMIT 1
),
active_packs AS (
SELECT target_pack_id AS pack_id
WHERE target_pack_id IS NOT NULL
AND EXISTS (
SELECT 1 FROM public.question_packs qp
WHERE qp.id = target_pack_id
AND (qp.is_premium = FALSE OR v_has_premium = TRUE)
)
UNION ALL
SELECT cp.pack_id FROM public.couple_packs cp
INNER JOIN public.question_packs qp ON qp.id = cp.pack_id
WHERE target_pack_id IS NULL
AND cp.couple_id = v_couple_id
AND cp.enabled = TRUE
AND (qp.is_premium = FALSE OR v_has_premium = TRUE)
AND EXISTS (SELECT 1 FROM user_config_exists)
UNION ALL
SELECT p.id AS pack_id FROM public.question_packs p
WHERE target_pack_id IS NULL
AND p.is_public = TRUE
AND (p.is_premium = FALSE OR v_has_premium = TRUE)
AND NOT EXISTS (SELECT 1 FROM user_config_exists)
)
SELECT
q.id,
CASE
WHEN q.partner_text IS NOT NULL AND EXISTS (
SELECT 1 FROM public.responses r
WHERE r.question_id = q.id
AND r.couple_id = v_couple_id
AND r.user_id != v_user_id
) THEN q.partner_text
ELSE q.text
END as text,
q.partner_text,
q.partner_text IS NOT NULL as is_two_part,
q.pack_id,
q.intensity,
EXISTS (
SELECT 1 FROM public.responses r
WHERE r.question_id = q.id
AND r.couple_id = v_couple_id
AND r.user_id != v_user_id
) AS partner_answered,
q.allowed_couple_genders,
q.target_user_genders
FROM public.questions q
WHERE q.pack_id IN (SELECT ap.pack_id FROM active_packs ap)
AND NOT EXISTS (
SELECT 1 FROM public.responses r
WHERE r.question_id = q.id
AND r.user_id = v_user_id
)
AND (
q.allowed_couple_genders IS NULL
OR v_couple_type IS NULL
OR v_couple_type = ANY(q.allowed_couple_genders)
)
AND (
q.target_user_genders IS NULL
OR v_user_gender = ANY(q.target_user_genders)
OR EXISTS (
SELECT 1 FROM public.responses r
WHERE r.question_id = q.id
AND r.couple_id = v_couple_id
AND r.user_id != v_user_id
)
)
-- Filter by user's max_intensity preference
AND (
q.intensity IS NULL
OR q.intensity <= v_user_max_intensity
);
END;
$$;
COMMENT ON FUNCTION get_recommended_questions(UUID) IS 'Returns recommended questions for user filtered by their intensity preference. When user is too far ahead of partner (answer gap threshold exceeded), returns empty.';
Binary file not shown.

Before

Width:  |  Height:  |  Size: 755 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 613 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 384 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 646 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 863 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 966 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 780 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 979 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 314 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 703 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 825 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

+58 -96
View File
@@ -45,6 +45,7 @@
"openai": "^4.24.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.12.0",
"react-router-dom": "^6.21.0",
"recharts": "^3.6.0",
"sonner": "^1.3.1",
@@ -183,6 +184,7 @@
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
@@ -586,7 +588,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-firefox-class-in-computed-class-key/-/plugin-bugfix-firefox-class-in-computed-class-key-7.28.5.tgz",
"integrity": "sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1",
"@babel/traverse": "^7.28.5"
@@ -603,7 +604,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-class-field-initializer-scope/-/plugin-bugfix-safari-class-field-initializer-scope-7.27.1.tgz",
"integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -619,7 +619,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.27.1.tgz",
"integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -635,7 +634,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.27.1.tgz",
"integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1",
"@babel/helper-skip-transparent-expression-wrappers": "^7.27.1",
@@ -653,7 +651,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.28.3.tgz",
"integrity": "sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1",
"@babel/traverse": "^7.28.3"
@@ -754,7 +751,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz",
"integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6.9.0"
},
@@ -875,7 +871,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.27.1.tgz",
"integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -1062,7 +1057,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz",
"integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.18.6",
"@babel/helper-plugin-utils": "^7.18.6"
@@ -1128,7 +1122,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.27.1.tgz",
"integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -1175,7 +1168,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.28.3.tgz",
"integrity": "sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-create-class-features-plugin": "^7.28.3",
"@babel/helper-plugin-utils": "^7.27.1"
@@ -1244,7 +1236,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.27.1.tgz",
"integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.27.1",
"@babel/helper-plugin-utils": "^7.27.1"
@@ -1261,7 +1252,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.27.1.tgz",
"integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -1277,7 +1267,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-named-capturing-groups-regex/-/plugin-transform-duplicate-named-capturing-groups-regex-7.27.1.tgz",
"integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.27.1",
"@babel/helper-plugin-utils": "^7.27.1"
@@ -1294,7 +1283,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.27.1.tgz",
"integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -1310,7 +1298,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.28.0.tgz",
"integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1",
"@babel/plugin-transform-destructuring": "^7.28.0"
@@ -1327,7 +1314,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.28.5.tgz",
"integrity": "sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -1407,7 +1393,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.27.1.tgz",
"integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -1453,7 +1438,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.27.1.tgz",
"integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -1469,7 +1453,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.27.1.tgz",
"integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-module-transforms": "^7.27.1",
"@babel/helper-plugin-utils": "^7.27.1"
@@ -1502,7 +1485,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.28.5.tgz",
"integrity": "sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-module-transforms": "^7.28.3",
"@babel/helper-plugin-utils": "^7.27.1",
@@ -1521,7 +1503,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.27.1.tgz",
"integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-module-transforms": "^7.27.1",
"@babel/helper-plugin-utils": "^7.27.1"
@@ -1554,7 +1535,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.27.1.tgz",
"integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -1619,7 +1599,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.27.1.tgz",
"integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1",
"@babel/helper-replace-supers": "^7.27.1"
@@ -1715,7 +1694,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.27.1.tgz",
"integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -1841,7 +1819,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-regexp-modifiers/-/plugin-transform-regexp-modifiers-7.27.1.tgz",
"integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.27.1",
"@babel/helper-plugin-utils": "^7.27.1"
@@ -1858,7 +1835,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.27.1.tgz",
"integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -1955,7 +1931,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.27.1.tgz",
"integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -1990,7 +1965,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.27.1.tgz",
"integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.27.1"
},
@@ -2006,7 +1980,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.27.1.tgz",
"integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.27.1",
"@babel/helper-plugin-utils": "^7.27.1"
@@ -2039,7 +2012,6 @@
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.27.1.tgz",
"integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-create-regexp-features-plugin": "^7.27.1",
"@babel/helper-plugin-utils": "^7.27.1"
@@ -2158,7 +2130,6 @@
"resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz",
"integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/helper-plugin-utils": "^7.0.0",
"@babel/types": "^7.4.4",
@@ -6268,6 +6239,7 @@
"resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.23.1.tgz",
"integrity": "sha512-Qd2kQ3yi6Y3+AcUlrHxSLlnBvpdCEMVGFlVBneVOjaFaPU61g1huc38g339ysXspwY1QZA2aNhrk/KlHGO+ewA==",
"license": "MIT",
"peer": true,
"dependencies": {
"merge-options": "^3.0.4"
},
@@ -6713,6 +6685,7 @@
"resolved": "https://registry.npmjs.org/@react-navigation/native/-/native-7.1.26.tgz",
"integrity": "sha512-RhKmeD0E2ejzKS6z8elAfdfwShpcdkYY8zJzvHYLq+wv183BBcElTeyMLcIX6wIn7QutXeI92Yi21t7aUWfqNQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"@react-navigation/core": "^7.13.7",
"escape-string-regexp": "^4.0.0",
@@ -7884,7 +7857,6 @@
"integrity": "sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/estree": "*",
"@types/json-schema": "*"
@@ -7896,7 +7868,6 @@
"integrity": "sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/eslint": "*",
"@types/estree": "*"
@@ -8110,6 +8081,7 @@
"integrity": "sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/prop-types": "*",
"csstype": "^3.2.2"
@@ -8121,6 +8093,7 @@
"integrity": "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==",
"devOptional": true,
"license": "MIT",
"peer": true,
"peerDependencies": {
"@types/react": "^18.0.0"
}
@@ -8237,7 +8210,6 @@
"integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/helper-numbers": "1.13.2",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2"
@@ -8248,24 +8220,21 @@
"resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz",
"integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-api-error": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz",
"integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-buffer": {
"version": "1.14.1",
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz",
"integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-numbers": {
"version": "1.13.2",
@@ -8273,7 +8242,6 @@
"integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/floating-point-hex-parser": "1.13.2",
"@webassemblyjs/helper-api-error": "1.13.2",
@@ -8285,8 +8253,7 @@
"resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz",
"integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@webassemblyjs/helper-wasm-section": {
"version": "1.14.1",
@@ -8294,7 +8261,6 @@
"integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-buffer": "1.14.1",
@@ -8308,7 +8274,6 @@
"integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@xtuc/ieee754": "^1.2.0"
}
@@ -8319,7 +8284,6 @@
"integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"dependencies": {
"@xtuc/long": "4.2.2"
}
@@ -8329,8 +8293,7 @@
"resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz",
"integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/@webassemblyjs/wasm-edit": {
"version": "1.14.1",
@@ -8338,7 +8301,6 @@
"integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-buffer": "1.14.1",
@@ -8356,7 +8318,6 @@
"integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-wasm-bytecode": "1.13.2",
@@ -8371,7 +8332,6 @@
"integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-buffer": "1.14.1",
@@ -8385,7 +8345,6 @@
"integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@webassemblyjs/helper-api-error": "1.13.2",
@@ -8401,7 +8360,6 @@
"integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@webassemblyjs/ast": "1.14.1",
"@xtuc/long": "4.2.2"
@@ -8422,16 +8380,14 @@
"resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz",
"integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==",
"dev": true,
"license": "BSD-3-Clause",
"peer": true
"license": "BSD-3-Clause"
},
"node_modules/@xtuc/long": {
"version": "4.2.2",
"resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz",
"integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==",
"dev": true,
"license": "Apache-2.0",
"peer": true
"license": "Apache-2.0"
},
"node_modules/abab": {
"version": "2.0.6",
@@ -8471,6 +8427,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -8495,7 +8452,6 @@
"integrity": "sha512-wKmbr/DDiIXzEOiWrTTUcDm24kQ2vGfZQvM2fwg2vXqR5uW6aapr7ObPtj1th32b9u90/Pf4AItvdTh42fBmVQ==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10.13.0"
},
@@ -8571,6 +8527,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz",
"integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==",
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"fast-uri": "^3.0.1",
@@ -9160,8 +9117,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
"integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==",
"license": "ISC",
"peer": true
"license": "ISC"
},
"node_modules/bplist-creator": {
"version": "0.0.7",
@@ -9225,6 +9181,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"baseline-browser-mapping": "^2.9.0",
"caniuse-lite": "^1.0.30001759",
@@ -9621,7 +9578,6 @@
"integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6.0"
}
@@ -10113,7 +10069,6 @@
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz",
"integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==",
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"boolbase": "^1.0.0",
"css-what": "^6.1.0",
@@ -10130,7 +10085,6 @@
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
"integrity": "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==",
"license": "MIT",
"peer": true,
"dependencies": {
"mdn-data": "2.0.14",
"source-map": "^0.6.1"
@@ -10144,7 +10098,6 @@
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"license": "BSD-3-Clause",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -10154,7 +10107,6 @@
"resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz",
"integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==",
"license": "BSD-2-Clause",
"peer": true,
"engines": {
"node": ">= 6"
},
@@ -10687,7 +10639,6 @@
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
"license": "MIT",
"peer": true,
"dependencies": {
"domelementtype": "^2.3.0",
"domhandler": "^5.0.2",
@@ -10707,8 +10658,7 @@
"url": "https://github.com/sponsors/fb55"
}
],
"license": "BSD-2-Clause",
"peer": true
"license": "BSD-2-Clause"
},
"node_modules/domexception": {
"version": "4.0.0",
@@ -10739,7 +10689,6 @@
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"domelementtype": "^2.3.0"
},
@@ -10755,7 +10704,6 @@
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"dom-serializer": "^2.0.0",
"domelementtype": "^2.3.0",
@@ -10899,7 +10847,8 @@
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/emoji-mart/-/emoji-mart-5.6.0.tgz",
"integrity": "sha512-eJp3QRe79pjwa+duv+n7+5YsNhRcMl812EcFVwrnRvYKoNPoQb5qxU8DG6Bgwji0akHdp6D4Ln6tYLG58MFSow==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/emoji-regex": {
"version": "8.0.0",
@@ -10931,7 +10880,6 @@
"integrity": "sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"graceful-fs": "^4.2.4",
"tapable": "^2.2.0"
@@ -10945,7 +10893,6 @@
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"license": "BSD-2-Clause",
"peer": true,
"engines": {
"node": ">=0.12"
},
@@ -11003,8 +10950,7 @@
"resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz",
"integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/es-object-atoms": {
"version": "1.1.1",
@@ -11148,7 +11094,6 @@
"integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==",
"dev": true,
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^4.1.1"
@@ -11163,7 +11108,6 @@
"integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==",
"dev": true,
"license": "BSD-2-Clause",
"peer": true,
"engines": {
"node": ">=4.0"
}
@@ -11187,7 +11131,6 @@
"integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==",
"dev": true,
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"estraverse": "^5.2.0"
},
@@ -11571,6 +11514,7 @@
"resolved": "https://registry.npmjs.org/expo/-/expo-52.0.48.tgz",
"integrity": "sha512-/HR/vuo57KGEWlvF3GWaquwEAjXuA5hrOCsaLcZ3pMSA8mQ27qKd1jva4GWzpxXYedlzs/7LLP1XpZo6hXTsog==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.20.0",
"@expo/cli": "0.22.27",
@@ -11720,6 +11664,7 @@
"resolved": "https://registry.npmjs.org/expo-constants/-/expo-constants-17.0.8.tgz",
"integrity": "sha512-XfWRyQAf1yUNgWZ1TnE8pFBMqGmFP5Gb+SFSgszxDdOoheB/NI5D4p7q86kI2fvGyfTrxAe+D+74nZkfsGvUlg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@expo/config": "~10.0.11",
"@expo/env": "~0.4.2"
@@ -11802,6 +11747,7 @@
"resolved": "https://registry.npmjs.org/expo-file-system/-/expo-file-system-18.0.12.tgz",
"integrity": "sha512-HAkrd/mb8r+G3lJ9MzmGeuW2B+BxQR1joKfeCyY4deLl1zoZ48FrAWjgZjHK9aHUVhJ0ehzInu/NQtikKytaeg==",
"license": "MIT",
"peer": true,
"dependencies": {
"web-streams-polyfill": "^3.3.2"
},
@@ -11902,6 +11848,7 @@
"resolved": "https://registry.npmjs.org/expo-linking/-/expo-linking-7.0.5.tgz",
"integrity": "sha512-3KptlJtcYDPWohk0MfJU75MJFh2ybavbtcSd84zEPfw9s1q3hjimw3sXnH03ZxP54kiEWldvKmmnGcVffBDB1g==",
"license": "MIT",
"peer": true,
"dependencies": {
"expo-constants": "~17.0.5",
"invariant": "^2.2.4"
@@ -12669,8 +12616,7 @@
"resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz",
"integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==",
"dev": true,
"license": "BSD-2-Clause",
"peer": true
"license": "BSD-2-Clause"
},
"node_modules/globby": {
"version": "11.1.0",
@@ -13670,6 +13616,7 @@
"integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@jest/core": "^29.7.0",
"@jest/types": "^29.6.3",
@@ -14112,8 +14059,7 @@
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.25.0-rc-6230622a1a-20240610.tgz",
"integrity": "sha512-GTIQdJXthps5mgkIFo7yAq03M0QQYTfN8z+GrnMC/SCKFSuyFP5tk2BMaaWUsVy4u4r+dTLdiXH8JEivVls0Bw==",
"dev": true,
"license": "MIT",
"peer": true
"license": "MIT"
},
"node_modules/jest-get-type": {
"version": "29.6.3",
@@ -14688,6 +14634,7 @@
"integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"jiti": "bin/jiti.js"
}
@@ -14985,6 +14932,7 @@
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.27.0.tgz",
"integrity": "sha512-8f7aNmS1+etYSLHht0fQApPc2kNO8qGRutifN5rVIc6Xo6ABsEbqOr758UwI7ALVbTt4x1fllKt0PYgzD9S3yQ==",
"license": "MPL-2.0",
"peer": true,
"dependencies": {
"detect-libc": "^1.0.3"
},
@@ -15233,7 +15181,6 @@
"integrity": "sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6.11.5"
},
@@ -15474,8 +15421,7 @@
"version": "2.0.14",
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz",
"integrity": "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==",
"license": "CC0-1.0",
"peer": true
"license": "CC0-1.0"
},
"node_modules/memoize-one": {
"version": "5.2.1",
@@ -16321,7 +16267,6 @@
"resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz",
"integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==",
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"boolbase": "^1.0.0"
},
@@ -16990,6 +16935,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -17392,7 +17338,6 @@
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"safe-buffer": "^5.1.0"
}
@@ -17426,6 +17371,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
"license": "MIT",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0"
},
@@ -17469,6 +17415,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
"license": "MIT",
"peer": true,
"dependencies": {
"loose-envify": "^1.1.0",
"scheduler": "^0.23.2"
@@ -17512,17 +17459,28 @@
"react-dom": "^16.6.0 || ^17.0.0 || ^18.0.0"
}
},
"node_modules/react-icons": {
"version": "4.12.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-4.12.0.tgz",
"integrity": "sha512-IBaDuHiShdZqmfc/TwHu6+d6k2ltNCf3AszxNmjJc1KUfXdEeRJOKyNvLmAHaarhzGmTSVygNdyu8/opXv2gaw==",
"license": "MIT",
"peerDependencies": {
"react": "*"
}
},
"node_modules/react-is": {
"version": "19.2.3",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-19.2.3.tgz",
"integrity": "sha512-qJNJfu81ByyabuG7hPFEbXqNcWSU3+eVus+KJs+0ncpGfMyYdvSmxiJxbWR65lYi1I+/0HBcliO029gc4F+PnA==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/react-native": {
"version": "0.76.9",
"resolved": "https://registry.npmjs.org/react-native/-/react-native-0.76.9.tgz",
"integrity": "sha512-+LRwecWmTDco7OweGsrECIqJu0iyrREd6CTCgC/uLLYipiHvk+MH9nd6drFtCw/6Blz6eoKTcH9YTTJusNtrWg==",
"license": "MIT",
"peer": true,
"dependencies": {
"@jest/create-cache-key-function": "^29.6.3",
"@react-native/assets-registry": "0.76.9",
@@ -17691,6 +17649,7 @@
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-3.16.7.tgz",
"integrity": "sha512-qoUUQOwE1pHlmQ9cXTJ2MX9FQ9eHllopCLiWOkDkp6CER95ZWeXhJCP4cSm6AD4jigL5jHcZf/SkWrg8ttZUsw==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/plugin-transform-arrow-functions": "^7.0.0-0",
"@babel/plugin-transform-class-properties": "^7.0.0-0",
@@ -17715,6 +17674,7 @@
"resolved": "https://registry.npmjs.org/react-native-safe-area-context/-/react-native-safe-area-context-4.12.0.tgz",
"integrity": "sha512-ukk5PxcF4p3yu6qMZcmeiZgowhb5AsKRnil54YFUUAXVIS7PJcMHGGC+q44fCiBg44/1AJk5njGMez1m9H0BVQ==",
"license": "MIT",
"peer": true,
"peerDependencies": {
"react": "*",
"react-native": "*"
@@ -17725,6 +17685,7 @@
"resolved": "https://registry.npmjs.org/react-native-screens/-/react-native-screens-4.4.0.tgz",
"integrity": "sha512-c7zc7Zwjty6/pGyuuvh9gK3YBYqHPOxrhXfG1lF4gHlojQSmIx2piNbNaV+Uykj+RDTmFXK0e/hA+fucw/Qozg==",
"license": "MIT",
"peer": true,
"dependencies": {
"react-freeze": "^1.0.0",
"warn-once": "^0.1.0"
@@ -17767,6 +17728,7 @@
"resolved": "https://registry.npmjs.org/react-native-web/-/react-native-web-0.19.13.tgz",
"integrity": "sha512-etv3bN8rJglrRCp/uL4p7l8QvUNUC++QwDbdZ8CB7BvZiMvsxfFIRM1j04vxNldG3uo2puRd6OSWR3ibtmc29A==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.18.6",
"@react-native/normalize-colors": "^0.74.1",
@@ -17865,6 +17827,7 @@
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-9.2.0.tgz",
"integrity": "sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==",
"license": "MIT",
"peer": true,
"dependencies": {
"@types/use-sync-external-store": "^0.0.6",
"use-sync-external-store": "^1.4.0"
@@ -18021,6 +17984,7 @@
"integrity": "sha512-KkAgygexHUkQqtvvx/otwxtuFu5cVjfzTCtjXLH9boS19/Nbtg84zS7wIQn39G8IlrhThBpQsMKkq5ZHZIYFXA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"react-is": "^18.3.1",
"react-shallow-renderer": "^16.15.0",
@@ -18201,7 +18165,8 @@
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/redux/-/redux-5.0.1.tgz",
"integrity": "sha512-M9/ELqF6fy8FwmkpnF0S3YKOqMyoWJ4+CS5Efg2ct3oY9daQvd/Pc71FpGZsVsbl3Cpb+IIcjBDUnnyBdQbq4w==",
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/redux-thunk": {
"version": "3.1.0",
@@ -18706,7 +18671,6 @@
"integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"dev": true,
"license": "BSD-3-Clause",
"peer": true,
"dependencies": {
"randombytes": "^2.1.0"
}
@@ -19504,7 +19468,6 @@
"integrity": "sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=6"
},
@@ -19679,6 +19642,7 @@
"resolved": "https://registry.npmjs.org/terser/-/terser-5.44.1.tgz",
"integrity": "sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==",
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"@jridgewell/source-map": "^0.3.3",
"acorn": "^8.15.0",
@@ -19698,7 +19662,6 @@
"integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@jridgewell/trace-mapping": "^0.3.25",
"jest-worker": "^27.4.5",
@@ -19734,7 +19697,6 @@
"integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@types/node": "*",
"merge-stream": "^2.0.0",
@@ -19750,7 +19712,6 @@
"integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"has-flag": "^4.0.0"
},
@@ -20365,6 +20326,7 @@
"integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"esbuild": "^0.21.3",
"postcss": "^8.4.43",
@@ -20459,7 +20421,6 @@
"integrity": "sha512-e6vZvY6xboSwLz2GD36c16+O/2Z6fKvIf4pOXptw2rY9MVwE/TXc6RGqxD3I3x0a28lwBY7DE+76uTPSsBrrCA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"glob-to-regexp": "^0.4.1",
"graceful-fs": "^4.1.2"
@@ -20548,7 +20509,6 @@
"integrity": "sha512-yd1RBzSGanHkitROoPFd6qsrxt+oFhg/129YzheDGqeustzX0vTZJZsSsQjVQC4yzBQ56K55XU8gaNCtIzOnTg==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10.13.0"
}
@@ -20739,6 +20699,7 @@
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=10.0.0"
},
@@ -20845,6 +20806,7 @@
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
"license": "ISC",
"peer": true,
"engines": {
"node": ">= 6"
}
+15 -15
View File
@@ -16,46 +16,46 @@ const DIMENSIONS = {
// Screenshot configurations with marketing text
const SCREENSHOTS = [
{
source: "Simulator Screenshot - iPhone 16 Pro - 2025-12-30 at 19.57.14.png",
source: "Simulator Screenshot - iPhone 16e - 2026-01-08 at 19.18.40.png",
headline: "Your Couple Dashboard",
subheadline: "Track matches, packs & explore together",
outputName: "01-home",
},
{
source: "Simulator Screenshot - iPhone 16 Pro - 2025-12-30 at 20.10.53.png",
source: "Simulator Screenshot - iPhone 16e - 2026-01-08 at 19.10.03.png",
headline: "Curated Question Packs",
subheadline: "From first dates to spicy adventures",
outputName: "02-packs",
},
{
source: "Simulator Screenshot - iPhone 16 Pro - 2025-12-30 at 19.57.35.png",
source: "Simulator Screenshot - iPhone 16e - 2026-01-08 at 19.06.40.png",
headline: "Swipe on Questions",
subheadline: "Answer yes, no, or maybe together",
outputName: "03-swipe",
},
{
source: "Simulator Screenshot - iPhone 16 Pro - 2025-12-30 at 21.00.55.png",
headline: "Express Yourself",
subheadline: "Swipe right on what excites you",
outputName: "04-swipe-yes",
},
{
source: "Simulator Screenshot - iPhone 16 Pro - 2025-12-30 at 19.57.51.png",
source: "Simulator Screenshot - iPhone 16e - 2026-01-08 at 19.07.29.png",
headline: "It's a Match!",
subheadline: "Celebrate when you both say yes",
outputName: "05-match",
outputName: "04-match",
},
{
source: "Simulator Screenshot - iPhone 16 Pro - 2025-12-30 at 20.02.50.png",
source: "Simulator Screenshot - iPhone 16e - 2026-01-08 at 19.09.54.png",
headline: "Discover Your Matches",
subheadline: "See where you both agree",
outputName: "06-home-matches",
outputName: "05-matches",
},
{
source: "Simulator Screenshot - iPhone 16 Pro - 2025-12-30 at 20.01.31.png",
source: "Simulator Screenshot - iPhone 16e - 2026-01-08 at 19.08.25.png",
headline: "Chat About It",
subheadline: "Every match unlocks a conversation",
outputName: "07-chat",
outputName: "06-chat",
},
{
source: "Simulator Screenshot - iPhone 16e - 2026-01-08 at 19.09.48.png",
headline: "Set Your Comfort Zone",
subheadline: "Customize your intimacy preferences",
outputName: "07-settings",
},
];
Binary file not shown.

Before

Width:  |  Height:  |  Size: 629 KiB

After

Width:  |  Height:  |  Size: 658 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 858 KiB

After

Width:  |  Height:  |  Size: 837 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 852 KiB

After

Width:  |  Height:  |  Size: 757 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 567 KiB

After

Width:  |  Height:  |  Size: 561 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 757 KiB

After

Width:  |  Height:  |  Size: 683 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 751 KiB

After

Width:  |  Height:  |  Size: 596 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 381 KiB

After

Width:  |  Height:  |  Size: 592 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 502 KiB

After

Width:  |  Height:  |  Size: 748 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 497 KiB

After

Width:  |  Height:  |  Size: 628 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 300 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 437 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 588 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 589 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 256 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 330 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 328 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 855 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 578 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 798 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 790 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 387 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 534 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 525 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 469 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 591 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 KiB