Progress update cleanup and UI improvements.
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Text } from "react-native";
|
||||
import { Card } from "react-native-paper";
|
||||
import { Button, Card } from "react-native-paper";
|
||||
|
||||
export default function ErrorDisplay({ errorMessage, error }) {
|
||||
export default function ErrorDisplay({ errorMessage, error, onDismiss }) {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<Card style={{ margin: 8, backgroundColor: "#ffdddd" }}>
|
||||
@@ -14,6 +14,11 @@ export default function ErrorDisplay({ errorMessage, error }) {
|
||||
error ||
|
||||
"An unknown error has occured."}
|
||||
</Text>
|
||||
{onDismiss ? (
|
||||
<Card.Actions>
|
||||
<Button onPress={onDismiss}>{t("general.labels.dismiss")}</Button>
|
||||
</Card.Actions>
|
||||
) : null}
|
||||
</Card.Content>
|
||||
</Card>
|
||||
);
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
View,
|
||||
} from "react-native";
|
||||
import ImageView from "react-native-image-viewing";
|
||||
import { ActivityIndicator } from "react-native-paper";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import env from "../../env";
|
||||
@@ -119,6 +120,7 @@ export function JobDocumentsComponent({ bodyshop }) {
|
||||
getPhotos();
|
||||
}, [getPhotos]);
|
||||
|
||||
if (loading) return <ActivityIndicator style={{ flex: 1 }} size="large" />;
|
||||
if (error) {
|
||||
return <ErrorDisplay message={JSON.stringify(error)} />;
|
||||
}
|
||||
|
||||
@@ -17,14 +17,13 @@ export default function JobLines() {
|
||||
skip: !jobId,
|
||||
});
|
||||
|
||||
console.log("*** ~ JobLines ~ error:", error);
|
||||
const { t } = useTranslation();
|
||||
const onRefresh = async () => {
|
||||
return refetch();
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <ActivityIndicator />;
|
||||
return <ActivityIndicator size="large" style={{ flex: 1 }} />;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
|
||||
@@ -25,7 +25,7 @@ export default function JobNotes() {
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return <ActivityIndicator />;
|
||||
return <ActivityIndicator size="large" style={{ flex: 1 }} />;
|
||||
}
|
||||
if (error) {
|
||||
return <ErrorDisplay message={JSON.stringify(error?.message)} />;
|
||||
|
||||
@@ -23,14 +23,13 @@ export default function JobTombstone() {
|
||||
});
|
||||
|
||||
const theme = useTheme();
|
||||
console.log("*** ~ JobTombstone ~ theme:", theme.colors);
|
||||
|
||||
const { t } = useTranslation();
|
||||
const onRefresh = async () => {
|
||||
return refetch();
|
||||
};
|
||||
if (loading) {
|
||||
return <ActivityIndicator />;
|
||||
return <ActivityIndicator size="large" style={{ flex: 1 }} />;
|
||||
}
|
||||
if (!data.jobs_by_pk) {
|
||||
return (
|
||||
|
||||
@@ -133,7 +133,12 @@ const styles = StyleSheet.create({
|
||||
borderWidth: StyleSheet.hairlineWidth,
|
||||
backdropFilter: "blur(20px)", // web only
|
||||
},
|
||||
cardContents: { flex: 1, flexDirection: "row", display: "flex" },
|
||||
cardContents: {
|
||||
flex: 1,
|
||||
flexDirection: "row",
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
},
|
||||
headerRow: {
|
||||
flexDirection: "row",
|
||||
alignItems: "flex-start",
|
||||
|
||||
56
components/settings/settings.jsx
Normal file
56
components/settings/settings.jsx
Normal file
@@ -0,0 +1,56 @@
|
||||
import SignOutButton from "@/components-old/sign-out-button/sign-out-button.component";
|
||||
import { toggleDeleteAfterUpload } from "@/redux/app/app.actions";
|
||||
import { selectDeleteAfterUpload } from "@/redux/app/app.selectors";
|
||||
import { selectBodyshop } from "@/redux/user/user.selectors";
|
||||
import { formatBytes } from "@/util/uploadUtils";
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import { StyleSheet, View } from "react-native";
|
||||
import { Button, Divider, Text } from "react-native-paper";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import UploadDeleteSwitch from "./upload-delete-switch";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
bodyshop: selectBodyshop,
|
||||
deleteAfterUpload: selectDeleteAfterUpload,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
toggleDeleteAfterUpload: () => dispatch(toggleDeleteAfterUpload()),
|
||||
});
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(Tab);
|
||||
|
||||
function Tab({ bodyshop, deleteAfterUpload, toggleDeleteAfterUpload }) {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text variant="titleLarge">Settings</Text>
|
||||
<Text>
|
||||
Media Storage:{" "}
|
||||
{bodyshop?.uselocalmediaserver
|
||||
? bodyshop.localmediaserverhttp
|
||||
: "Cloud"}
|
||||
</Text>
|
||||
{!bodyshop?.uselocalmediaserver && (
|
||||
<Text>Job Size Limit: {formatBytes(bodyshop?.jobsizelimit)}</Text>
|
||||
)}
|
||||
<UploadDeleteSwitch />
|
||||
<Button
|
||||
onPress={() => {
|
||||
AsyncStorage.removeItem("persist:root");
|
||||
}}
|
||||
>
|
||||
Clear Storage
|
||||
</Button>
|
||||
<Divider />
|
||||
<SignOutButton />
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
},
|
||||
});
|
||||
53
components/settings/upload-delete-switch.jsx
Normal file
53
components/settings/upload-delete-switch.jsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import React from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { StyleSheet, Text, View } from "react-native";
|
||||
import { Switch } from "react-native-paper";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import { toggleDeleteAfterUpload } from "../../redux/app/app.actions";
|
||||
import { selectDeleteAfterUpload } from "../../redux/app/app.selectors";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
deleteAfterUpload: selectDeleteAfterUpload,
|
||||
});
|
||||
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
toggleDeleteAfterUpload: () => dispatch(toggleDeleteAfterUpload()),
|
||||
});
|
||||
|
||||
export function UploadDeleteSwitch({
|
||||
deleteAfterUpload,
|
||||
toggleDeleteAfterUpload,
|
||||
}) {
|
||||
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.text}>
|
||||
{t("mediabrowser.labels.deleteafterupload")}
|
||||
</Text>
|
||||
<Switch
|
||||
// trackColor={{ false: '#767577', true: '#81b0ff' }}
|
||||
// thumbColor={deleteAfterUpload ? 'tomato' : '#f4f3f4'}
|
||||
//ios_backgroundColor="#3e3e3e"
|
||||
onValueChange={() => {
|
||||
toggleDeleteAfterUpload();
|
||||
}}
|
||||
value={deleteAfterUpload}
|
||||
/>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
const styles = StyleSheet.create({
|
||||
container: {
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
margin: 10,
|
||||
},
|
||||
|
||||
text: {
|
||||
flex: 1,
|
||||
},
|
||||
});
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(UploadDeleteSwitch);
|
||||
@@ -1,28 +1,53 @@
|
||||
import { clearUploadError } from "@/redux/photos/photos.actions";
|
||||
import theme from "@/util/theme";
|
||||
import { formatBytes } from "@/util/uploadUtils";
|
||||
import { ActivityIndicator, StyleSheet, Text, View } from "react-native";
|
||||
import { ProgressBar } from "react-native-paper";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { StyleSheet, View } from "react-native";
|
||||
import { ProgressBar, Text } from "react-native-paper";
|
||||
import { connect } from "react-redux";
|
||||
import { createStructuredSelector } from "reselect";
|
||||
import {
|
||||
selectPhotos,
|
||||
selectUploadProgress,
|
||||
selectPhotos,
|
||||
selectUploadError,
|
||||
selectUploadProgress,
|
||||
} from "../../redux/photos/photos.selectors";
|
||||
import ErrorDisplay from "../error/error-display";
|
||||
|
||||
const mapStateToProps = createStructuredSelector({
|
||||
photos: selectPhotos,
|
||||
photoUploadProgress: selectUploadProgress,
|
||||
uploadError: selectUploadError,
|
||||
});
|
||||
const mapDispatchToProps = (dispatch) => ({
|
||||
clearError: () => dispatch(clearUploadError()),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, null)(UploadProgress);
|
||||
export default connect(mapStateToProps, mapDispatchToProps)(UploadProgress);
|
||||
|
||||
export function UploadProgress({ photos, photoUploadProgress }) {
|
||||
export function UploadProgress({
|
||||
photos,
|
||||
photoUploadProgress,
|
||||
uploadError,
|
||||
clearError,
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
if (photos?.length === 0) return null;
|
||||
if (uploadError)
|
||||
return <ErrorDisplay error={uploadError} onDismiss={clearError} />;
|
||||
return (
|
||||
<View style={styles.modalContainer}>
|
||||
<View style={styles.modal}>
|
||||
<Text variant="titleLarge" style={styles.title}>
|
||||
{t("general.labels.uploadprogress")}
|
||||
</Text>
|
||||
|
||||
{Object.keys(photoUploadProgress).map((key) => (
|
||||
<View key={key} style={styles.progressItem}>
|
||||
<Text style={styles.progressText}>
|
||||
<Text
|
||||
style={styles.progressText}
|
||||
numberOfLines={1}
|
||||
ellipsizeMode="tail"
|
||||
>
|
||||
{photoUploadProgress[key].fileName}
|
||||
</Text>
|
||||
<View style={styles.progressBarContainer}>
|
||||
@@ -42,38 +67,14 @@ export function UploadProgress({ photos, photoUploadProgress }) {
|
||||
>
|
||||
<Text>{`${formatBytes(
|
||||
photoUploadProgress[key].loaded /
|
||||
(((photoUploadProgress[key].uploadEnd || new Date()) -
|
||||
photoUploadProgress[key].uploadStart) /
|
||||
(((photoUploadProgress[key].endTime || new Date()) -
|
||||
photoUploadProgress[key].startTime) /
|
||||
1000)
|
||||
)}/sec`}</Text>
|
||||
{photoUploadProgress[key].percent === 1 && (
|
||||
<>
|
||||
<ActivityIndicator style={{ marginLeft: 12 }} />
|
||||
<Text style={{ marginLeft: 4 }}>Processing...</Text>
|
||||
</>
|
||||
)}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
))}
|
||||
<View style={styles.centeredView}>
|
||||
{
|
||||
// progress.statusText ? (
|
||||
// <>
|
||||
// <ActivityIndicator style={{ marginLeft: 12 }} />
|
||||
// <Text style={{ marginLeft: 4 }}>{progress.statusText}</Text>
|
||||
// <Divider />
|
||||
// </>
|
||||
// ) : (
|
||||
// <>
|
||||
// <Text>{`${progress.totalFilesCompleted} of ${progress.totalFiles} uploaded.`}</Text>
|
||||
// <Text>{`${formatBytes(progress.totalUploaded)} of ${formatBytes(
|
||||
// progress.totalToUpload
|
||||
// )} uploaded.`}</Text>
|
||||
// </>
|
||||
// )
|
||||
}
|
||||
</View>
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
@@ -81,17 +82,19 @@ export function UploadProgress({ photos, photoUploadProgress }) {
|
||||
const styles = StyleSheet.create({
|
||||
modalContainer: {
|
||||
display: "flex",
|
||||
flex: 1,
|
||||
// flex: 1,
|
||||
marginTop: 14,
|
||||
marginBottom: 14,
|
||||
justifyContent: "center",
|
||||
},
|
||||
modal: {
|
||||
//flex: 1,
|
||||
display: "flex",
|
||||
marginLeft: 20,
|
||||
marginRight: 20,
|
||||
backgroundColor: "white",
|
||||
marginLeft: 12,
|
||||
marginRight: 12,
|
||||
backgroundColor: theme.colors.elevation.level3,
|
||||
borderRadius: 20,
|
||||
padding: 18,
|
||||
paddingTop: 12,
|
||||
shadowColor: "#000",
|
||||
shadowOffset: {
|
||||
width: 0,
|
||||
@@ -101,6 +104,13 @@ const styles = StyleSheet.create({
|
||||
shadowRadius: 4,
|
||||
elevation: 5,
|
||||
},
|
||||
title: {
|
||||
alignSelf: "center",
|
||||
alignItems: "center",
|
||||
marginBottom: 12,
|
||||
paddingLeft: 12,
|
||||
paddingRight: 12,
|
||||
},
|
||||
centeredView: {
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
@@ -116,6 +126,12 @@ const styles = StyleSheet.create({
|
||||
},
|
||||
progressText: {
|
||||
flex: 1,
|
||||
flexShrink: 1, // allow shrinking so ellipsis can appear
|
||||
minWidth: 0, // ensures proper shrinking inside a flex row (especially on web)
|
||||
// (Optional) If you find web still not clipping, you can uncomment the next lines:
|
||||
// overflow: 'hidden',
|
||||
// textOverflow: 'ellipsis',
|
||||
// whiteSpace: 'nowrap',
|
||||
},
|
||||
progressBarContainer: {
|
||||
flex: 3,
|
||||
|
||||
Reference in New Issue
Block a user