268 lines
8.4 KiB
JavaScript
268 lines
8.4 KiB
JavaScript
import { selectDeleteAfterUpload } from "@/redux/app/app.selectors";
|
|
import { signOutStart } from "@/redux/user/user.actions";
|
|
import { selectBodyshop, selectCurrentUser } from "@/redux/user/user.selectors";
|
|
import { registerForPushNotificationsAsync } from "@/util/notificationHandler";
|
|
import { formatBytes } from "@/util/uploadUtils";
|
|
import AsyncStorage from "@react-native-async-storage/async-storage";
|
|
import * as Application from "expo-application";
|
|
import Constants from "expo-constants";
|
|
import * as Notifications from "expo-notifications";
|
|
import * as Updates from "expo-updates";
|
|
import { useEffect, useState } from "react";
|
|
import { useTranslation } from "react-i18next";
|
|
import { Alert, ScrollView, StyleSheet, View } from "react-native";
|
|
import { Button, Card, Divider, List, Text } from "react-native-paper";
|
|
import { SafeAreaView } from "react-native-safe-area-context";
|
|
import { connect } from "react-redux";
|
|
import { createStructuredSelector } from "reselect";
|
|
import { ThemeSelector } from "../theme-selector/theme-selector";
|
|
import UploadDeleteSwitch from "./upload-delete-switch";
|
|
const mapStateToProps = createStructuredSelector({
|
|
bodyshop: selectBodyshop,
|
|
deleteAfterUpload: selectDeleteAfterUpload,
|
|
currentUser: selectCurrentUser,
|
|
});
|
|
|
|
const mapDispatchToProps = (dispatch) => ({
|
|
signOutStart: () => dispatch(signOutStart()),
|
|
});
|
|
export default connect(mapStateToProps, mapDispatchToProps)(Tab);
|
|
|
|
function Tab({ bodyshop, currentUser, signOutStart }) {
|
|
const { t } = useTranslation();
|
|
const [permissionState, setPermissionState] = useState(null);
|
|
|
|
useEffect(() => {
|
|
(async () => {
|
|
const status = await Notifications.getPermissionsAsync();
|
|
|
|
setPermissionState(status);
|
|
})();
|
|
}, []);
|
|
|
|
const handleClearStorage = () => {
|
|
Alert.alert(
|
|
"Clear Local Cache",
|
|
"This will remove cache and settings. Continue?",
|
|
[
|
|
{ text: "Cancel", style: "cancel" },
|
|
{
|
|
text: "Clear",
|
|
style: "destructive",
|
|
onPress: async () => {
|
|
try {
|
|
await AsyncStorage.removeItem("persist:root");
|
|
Alert.alert(
|
|
"Cleared",
|
|
"Local cache cleared. Please restart the app."
|
|
);
|
|
} catch (_e) {
|
|
Alert.alert("Error", "Unable to clear local cache.");
|
|
}
|
|
},
|
|
},
|
|
]
|
|
);
|
|
};
|
|
|
|
return (
|
|
<SafeAreaView style={{ flex: 1 }} edges={["top"]}>
|
|
<Text variant="headlineMedium" style={styles.title}>
|
|
{t("settings.titles.settings")}
|
|
</Text>
|
|
<ScrollView contentContainerStyle={styles.container}>
|
|
<Card style={styles.section} mode="outlined">
|
|
<Card.Title title="Storage" />
|
|
<Card.Content>
|
|
<List.Section>
|
|
<View style={styles.inlineRow}>
|
|
<Text style={styles.switchLabel}>
|
|
{t("mediabrowser.labels.deleteafterupload")}
|
|
</Text>
|
|
<UploadDeleteSwitch />
|
|
</View>
|
|
<List.Item
|
|
title="Media Storage"
|
|
description={
|
|
bodyshop?.uselocalmediaserver
|
|
? bodyshop.localmediaserverhttp
|
|
: "Cloud"
|
|
}
|
|
left={(props) => <List.Icon {...props} icon="database" />}
|
|
/>
|
|
{!bodyshop?.uselocalmediaserver && (
|
|
<List.Item
|
|
title="Job Size Limit"
|
|
description={
|
|
bodyshop?.jobsizelimit
|
|
? formatBytes(bodyshop.jobsizelimit)
|
|
: "Not specified"
|
|
}
|
|
left={(props) => <List.Icon {...props} icon="harddisk" />}
|
|
/>
|
|
)}
|
|
</List.Section>
|
|
</Card.Content>
|
|
<Card.Actions>
|
|
<Button onPress={handleClearStorage} icon="delete-outline">
|
|
{t("settings.actions.clearcache")}
|
|
</Button>
|
|
</Card.Actions>
|
|
</Card>
|
|
|
|
<Card style={styles.section} mode="outlined">
|
|
<Card.Title title={t("settings.labels.theme")} />
|
|
<Card.Content>
|
|
<List.Section>
|
|
<View style={styles.inlineRow}>
|
|
<ThemeSelector />
|
|
</View>
|
|
</List.Section>
|
|
</Card.Content>
|
|
<Card.Actions></Card.Actions>
|
|
</Card>
|
|
<Card style={styles.section} mode="outlined">
|
|
<Card.Title title="Notifications" />
|
|
<Card.Content>
|
|
<List.Section>
|
|
<View style={styles.inlineRow}>
|
|
<Text>{`${t("settings.labels.notificationsenabled")}: ${
|
|
permissionState?.granted === true ? "Yes" : "No"
|
|
}`}</Text>
|
|
</View>
|
|
</List.Section>
|
|
</Card.Content>
|
|
<Card.Actions>
|
|
<Button
|
|
icon="bell-outline"
|
|
disabled={permissionState?.granted === true}
|
|
onPress={async () => {
|
|
try {
|
|
await registerForPushNotificationsAsync();
|
|
} catch (error) {
|
|
Alert.alert(
|
|
"Error",
|
|
`Unable to register for notifications: ${error.message}`
|
|
);
|
|
console.log(
|
|
"Notification registration error:",
|
|
error,
|
|
error.stack
|
|
);
|
|
}
|
|
}}
|
|
>
|
|
{t("settings.actions.enablenotifications")}
|
|
</Button>
|
|
</Card.Actions>
|
|
</Card>
|
|
|
|
<Card style={styles.section} mode="outlined">
|
|
<Card.Content>
|
|
<Text style={styles.paragraph}>
|
|
{`${t("settings.labels.signedinshop")} ${
|
|
bodyshop?.shopname || bodyshop?.id || "Unknown"
|
|
}`}
|
|
</Text>
|
|
<Text style={styles.paragraph}>
|
|
{`${t("settings.labels.signedinuser")} ${
|
|
currentUser?.email || "Unknown"
|
|
}`}
|
|
</Text>
|
|
</Card.Content>
|
|
<Card.Actions>
|
|
<Button onPress={signOutStart}>
|
|
{t("general.actions.signout")}
|
|
</Button>
|
|
</Card.Actions>
|
|
</Card>
|
|
|
|
<Divider style={styles.divider} />
|
|
<Text style={styles.footerNote} variant="bodySmall">
|
|
{t("settings.labels.version", {
|
|
number: `${Constants.expoConfig.version}(${Application.nativeBuildVersion} - ${Constants.expoConfig.extra.expover})`,
|
|
})}
|
|
</Text>
|
|
<Button
|
|
mode="text"
|
|
onPress={() => {
|
|
Updates.checkForUpdateAsync()
|
|
.then(async (update) => {
|
|
if (update.isAvailable) {
|
|
const reloaded = await Updates.fetchUpdateAsync();
|
|
if (reloaded.isNew) {
|
|
Alert.alert(
|
|
"Update downloaded",
|
|
"The app will now restart to apply the update.",
|
|
[
|
|
{
|
|
text: "Restart Now",
|
|
onPress: () => {
|
|
Updates.reloadAsync();
|
|
},
|
|
},
|
|
]
|
|
);
|
|
}
|
|
} else {
|
|
Alert.alert(
|
|
"No Update Available",
|
|
"You are using the latest version of the app."
|
|
);
|
|
}
|
|
})
|
|
.catch((error) => {
|
|
Alert.alert(
|
|
"Update Error",
|
|
`An error occurred while checking for updates: ${error.message}`
|
|
);
|
|
});
|
|
}}
|
|
>
|
|
Check for Update
|
|
</Button>
|
|
</ScrollView>
|
|
</SafeAreaView>
|
|
);
|
|
}
|
|
|
|
const styles = StyleSheet.create({
|
|
container: {
|
|
paddingVertical: 24,
|
|
paddingHorizontal: 12,
|
|
paddingBottom: 96,
|
|
},
|
|
title: {
|
|
marginHorizontal: 12,
|
|
fontWeight: "600",
|
|
},
|
|
section: {
|
|
marginBottom: 20,
|
|
},
|
|
inlineRow: {
|
|
flexDirection: "row",
|
|
alignItems: "center",
|
|
justifyContent: "space-between",
|
|
paddingVertical: 8,
|
|
paddingHorizontal: 4,
|
|
},
|
|
switchLabel: {
|
|
fontSize: 16,
|
|
fontWeight: "500",
|
|
},
|
|
paragraph: {
|
|
marginBottom: 8,
|
|
},
|
|
actionsRow: {
|
|
justifyContent: "flex-end",
|
|
},
|
|
divider: {
|
|
marginTop: 8,
|
|
},
|
|
footerNote: {
|
|
textAlign: "center",
|
|
// color: "#666",
|
|
marginTop: 16,
|
|
},
|
|
});
|