chore(dev): mock seed for testing the Map without scanning
Adds a "Add mock plants" entry under a new Developer section in the Settings screen, gated by __DEV__ so it never ships in release. It calls useHistory.seedTestData() which prepends 5 fake ScanRecords spread across Bordeaux / Bourgogne / Champagne so all the map features (region chips, markers, rename) can be exercised without having to actually walk into a vineyard. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d30f4f250c
commit
06be3483d7
124
VinEye/src/data/mockSeed.ts
Normal file
124
VinEye/src/data/mockSeed.ts
Normal file
|
|
@ -0,0 +1,124 @@
|
||||||
|
import type { ScanRecord } from '@/types/detection';
|
||||||
|
|
||||||
|
function generateId(suffix: string): string {
|
||||||
|
return `seed-${Date.now()}-${suffix}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isoMinusDays(days: number): string {
|
||||||
|
return new Date(Date.now() - days * 24 * 60 * 60 * 1000).toISOString();
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildMockScans(): ScanRecord[] {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
id: generateId('1'),
|
||||||
|
createdAt: isoMinusDays(0),
|
||||||
|
xpEarned: 25,
|
||||||
|
latitude: 44.84,
|
||||||
|
longitude: -0.58,
|
||||||
|
locationCapturedAt: isoMinusDays(0),
|
||||||
|
customName: 'Vigne du potager',
|
||||||
|
detection: {
|
||||||
|
result: 'vine',
|
||||||
|
confidence: 0.94,
|
||||||
|
diseaseClass: 'healthy',
|
||||||
|
cepageId: 'cabernet_sauvignon',
|
||||||
|
timestamp: Date.now(),
|
||||||
|
allProbabilities: [
|
||||||
|
{ class: 'healthy', probability: 0.94 },
|
||||||
|
{ class: 'esca', probability: 0.03 },
|
||||||
|
{ class: 'black_rot', probability: 0.02 },
|
||||||
|
{ class: 'leaf_blight', probability: 0.01 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: generateId('2'),
|
||||||
|
createdAt: isoMinusDays(1),
|
||||||
|
xpEarned: 35,
|
||||||
|
latitude: 44.66,
|
||||||
|
longitude: -0.35,
|
||||||
|
locationCapturedAt: isoMinusDays(1),
|
||||||
|
detection: {
|
||||||
|
result: 'vine',
|
||||||
|
confidence: 0.81,
|
||||||
|
diseaseClass: 'esca',
|
||||||
|
diseaseSlug: 'esca',
|
||||||
|
cepageId: 'merlot',
|
||||||
|
timestamp: Date.now() - 86_400_000,
|
||||||
|
allProbabilities: [
|
||||||
|
{ class: 'esca', probability: 0.81 },
|
||||||
|
{ class: 'healthy', probability: 0.12 },
|
||||||
|
{ class: 'leaf_blight', probability: 0.05 },
|
||||||
|
{ class: 'black_rot', probability: 0.02 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: generateId('3'),
|
||||||
|
createdAt: isoMinusDays(2),
|
||||||
|
xpEarned: 30,
|
||||||
|
latitude: 47.32,
|
||||||
|
longitude: 4.83,
|
||||||
|
locationCapturedAt: isoMinusDays(2),
|
||||||
|
customName: 'Pinot du grand-père',
|
||||||
|
detection: {
|
||||||
|
result: 'vine',
|
||||||
|
confidence: 0.88,
|
||||||
|
diseaseClass: 'healthy',
|
||||||
|
cepageId: 'pinot_noir',
|
||||||
|
timestamp: Date.now() - 2 * 86_400_000,
|
||||||
|
allProbabilities: [
|
||||||
|
{ class: 'healthy', probability: 0.88 },
|
||||||
|
{ class: 'leaf_blight', probability: 0.07 },
|
||||||
|
{ class: 'esca', probability: 0.03 },
|
||||||
|
{ class: 'black_rot', probability: 0.02 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: generateId('4'),
|
||||||
|
createdAt: isoMinusDays(3),
|
||||||
|
xpEarned: 20,
|
||||||
|
latitude: 49.05,
|
||||||
|
longitude: 4.05,
|
||||||
|
locationCapturedAt: isoMinusDays(3),
|
||||||
|
detection: {
|
||||||
|
result: 'uncertain',
|
||||||
|
confidence: 0.55,
|
||||||
|
diseaseClass: 'leaf_blight',
|
||||||
|
diseaseSlug: 'leaf-blight',
|
||||||
|
cepageId: 'chardonnay',
|
||||||
|
timestamp: Date.now() - 3 * 86_400_000,
|
||||||
|
allProbabilities: [
|
||||||
|
{ class: 'leaf_blight', probability: 0.55 },
|
||||||
|
{ class: 'healthy', probability: 0.28 },
|
||||||
|
{ class: 'esca', probability: 0.10 },
|
||||||
|
{ class: 'black_rot', probability: 0.07 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: generateId('5'),
|
||||||
|
createdAt: isoMinusDays(4),
|
||||||
|
xpEarned: 35,
|
||||||
|
latitude: 44.92,
|
||||||
|
longitude: -0.62,
|
||||||
|
locationCapturedAt: isoMinusDays(4),
|
||||||
|
detection: {
|
||||||
|
result: 'vine',
|
||||||
|
confidence: 0.76,
|
||||||
|
diseaseClass: 'black_rot',
|
||||||
|
diseaseSlug: 'black-rot',
|
||||||
|
cepageId: 'cabernet_sauvignon',
|
||||||
|
timestamp: Date.now() - 4 * 86_400_000,
|
||||||
|
allProbabilities: [
|
||||||
|
{ class: 'black_rot', probability: 0.76 },
|
||||||
|
{ class: 'healthy', probability: 0.15 },
|
||||||
|
{ class: 'esca', probability: 0.06 },
|
||||||
|
{ class: 'leaf_blight', probability: 0.03 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
@ -12,6 +12,8 @@ import { useTranslation } from "react-i18next";
|
||||||
import { Ionicons } from "@expo/vector-icons";
|
import { Ionicons } from "@expo/vector-icons";
|
||||||
import i18n from "@/i18n";
|
import i18n from "@/i18n";
|
||||||
|
|
||||||
|
import { toast } from "sonner-native";
|
||||||
|
|
||||||
import { Text } from "@/components/ui/text";
|
import { Text } from "@/components/ui/text";
|
||||||
import { colors } from "@/theme/colors";
|
import { colors } from "@/theme/colors";
|
||||||
import { useGameProgress } from "@/hooks/useGameProgress";
|
import { useGameProgress } from "@/hooks/useGameProgress";
|
||||||
|
|
@ -30,7 +32,12 @@ export default function SettingsScreen() {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const navigation = useNavigation();
|
const navigation = useNavigation();
|
||||||
const { resetProgress } = useGameProgress();
|
const { resetProgress } = useGameProgress();
|
||||||
const { clearHistory } = useHistory();
|
const { clearHistory, seedTestData } = useHistory();
|
||||||
|
|
||||||
|
async function handleSeed() {
|
||||||
|
await seedTestData();
|
||||||
|
toast.success(t("settings.seedDone"));
|
||||||
|
}
|
||||||
|
|
||||||
function handleLanguageToggle() {
|
function handleLanguageToggle() {
|
||||||
const newLang = i18n.language === "fr" ? "en" : "fr";
|
const newLang = i18n.language === "fr" ? "en" : "fr";
|
||||||
|
|
@ -93,6 +100,16 @@ export default function SettingsScreen() {
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
const devItems: MenuItem[] = __DEV__
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
icon: "flask-outline",
|
||||||
|
label: t("settings.seedTestData"),
|
||||||
|
onPress: handleSeed,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
|
||||||
const dangerItems: MenuItem[] = [
|
const dangerItems: MenuItem[] = [
|
||||||
{
|
{
|
||||||
icon: "trash-outline",
|
icon: "trash-outline",
|
||||||
|
|
@ -187,6 +204,13 @@ export default function SettingsScreen() {
|
||||||
</View>
|
</View>
|
||||||
</TouchableOpacity>
|
</TouchableOpacity>
|
||||||
|
|
||||||
|
{devItems.length > 0 && (
|
||||||
|
<>
|
||||||
|
<Text style={styles.sectionLabel}>{t("settings.developer")}</Text>
|
||||||
|
{renderMenuGroup(devItems)}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
{renderMenuGroup(dangerItems)}
|
{renderMenuGroup(dangerItems)}
|
||||||
|
|
||||||
<Text style={styles.versionText}>VinEye • Version 1.0.0</Text>
|
<Text style={styles.versionText}>VinEye • Version 1.0.0</Text>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue