Refactor to using RNP & UI Updates.

This commit is contained in:
Patrick Fic
2021-03-11 19:10:27 -07:00
parent 59f6605a40
commit a912b4f1d7
26 changed files with 689 additions and 440 deletions

16
App.js
View File

@@ -26,29 +26,17 @@ const theme = {
...DefaultTheme, ...DefaultTheme,
colors: { colors: {
...DefaultTheme.colors, ...DefaultTheme.colors,
primary: "tomato", primary: "dodgerblue",
accent: "yellow", accent: "tomato",
}, },
}; };
export default class App extends React.Component { export default class App extends React.Component {
// constructor(props) {
// super(props);
// this.state = {
// isReady: false,
// };
// }
async componentDidMount() { async componentDidMount() {
logImEXEvent("imexmobile_app_start"); logImEXEvent("imexmobile_app_start");
//this.setState({ isReady: true });
} }
render() { render() {
// if (!this.state.isReady) {
// return <AppLoading />;
// }
return ( return (
<Provider store={store}> <Provider store={store}>
<PersistGate persistor={persistor}> <PersistGate persistor={persistor}>

View File

@@ -162,6 +162,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>dates</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>documents</name> <name>documents</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -225,6 +246,27 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>jobinfo</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>lines</name> <name>lines</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>
@@ -246,6 +288,132 @@
</translation> </translation>
</translations> </translations>
</concept_node> </concept_node>
<concept_node>
<name>lines_desc</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>lines_lb_hrs</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>lines_lbr_ty</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>lines_part_type</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>lines_price</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node>
<name>lines_qty</name>
<definition_loaded>false</definition_loaded>
<description></description>
<comment></comment>
<default_text></default_text>
<translations>
<translation>
<language>en-US</language>
<approved>false</approved>
</translation>
<translation>
<language>es-MX</language>
<approved>false</approved>
</translation>
<translation>
<language>fr-CA</language>
<approved>false</approved>
</translation>
</translations>
</concept_node>
<concept_node> <concept_node>
<name>nojobnotes</name> <name>nojobnotes</name>
<definition_loaded>false</definition_loaded> <definition_loaded>false</definition_loaded>

View File

@@ -1,8 +1,9 @@
import { useQuery } from "@apollo/client"; import { useQuery } from "@apollo/client";
import { Ionicons } from "@expo/vector-icons";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FlatList, RefreshControl } from "react-native"; import { FlatList, RefreshControl, View } from "react-native";
import { Button, List, Modal, Portal, Provider } from "react-native-paper"; import { Button, List, Modal, Portal, Searchbar } from "react-native-paper";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries"; import { QUERY_ALL_ACTIVE_JOBS } from "../../graphql/jobs.queries";
@@ -47,23 +48,80 @@ export function CameraSelectJob({
const showModal = () => setVisible(true); const showModal = () => setVisible(true);
const hideModal = () => setVisible(false); const hideModal = () => setVisible(false);
const containerStyle = { backgroundColor: "white", padding: 20 };
const onRefresh = async () => { const onRefresh = async () => {
return refetch(); return refetch();
}; };
const [searchQuery, setSearchQuery] = React.useState("");
const onChangeSearch = (query) => setSearchQuery(query);
const jobs = data
? searchQuery === ""
? data.jobs
: data.jobs.filter(
(j) =>
(j.ro_number || "")
.toString()
.toLowerCase()
.includes(searchQuery.toLowerCase()) ||
(j.ownr_co_nm || "")
.toLowerCase()
.includes(searchQuery.toLowerCase()) ||
(j.ownr_fn || "")
.toLowerCase()
.includes(searchQuery.toLowerCase()) ||
(j.ownr_ln || "")
.toLowerCase()
.includes(searchQuery.toLowerCase()) ||
(j.plate_no || "")
.toLowerCase()
.includes(searchQuery.toLowerCase()) ||
(j.v_model_desc || "")
.toLowerCase()
.includes(searchQuery.toLowerCase()) ||
(j.v_make_desc || "")
.toLowerCase()
.includes(searchQuery.toLowerCase())
)
: [];
return ( return (
<Provider> <>
<Portal> <Portal>
<Modal <Modal
visible={visible} visible={visible}
onDismiss={hideModal} onDismiss={hideModal}
contentContainerStyle={containerStyle} // eslint-disable-next-line react-native/no-color-literals
contentContainerStyle={{
paddingTop: 20,
paddingBottom: 20,
flex: 1,
backgroundColor: "white",
}}
> >
<View
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
margin: 8,
}}
>
<Button onPress={() => hideModal()}>
<Ionicons name="ios-arrow-back" size={32} color="dodgerblue" />
</Button>
<Searchbar
style={{ flex: 1 }}
onChangeText={onChangeSearch}
value={searchQuery}
/>
</View>
<FlatList <FlatList
refreshControl={ refreshControl={
<RefreshControl refreshing={loading} onRefresh={onRefresh} /> <RefreshControl refreshing={loading} onRefresh={onRefresh} />
} }
data={data.jobs} data={[{ id: "temp", ro_number: "Temporary Storage" }, ...jobs]}
keyExtractor={(item) => item.id} keyExtractor={(item) => item.id}
renderItem={(object) => ( renderItem={(object) => (
<List.Item <List.Item
@@ -71,8 +129,25 @@ export function CameraSelectJob({
setCameraJobId(object.item.id); setCameraJobId(object.item.id);
setCameraJob(object.item); setCameraJob(object.item);
hideModal(); hideModal();
setSearchQuery("");
}} }}
description={`${ left={() => {
if (object.item.id !== cameraJobId) return null;
return (
<Ionicons
name="ios-checkmark-circle"
size={24}
color="dodgerblue"
style={{ alignSelf: "center" }}
/>
);
}}
titleStyle={{
...(object.item.id === cameraJobId
? { color: "dodgerblue" }
: {}),
}}
title={`${
object.item.ro_number ? `${object.item.ro_number} - ` : `` object.item.ro_number ? `${object.item.ro_number} - ` : ``
}${object.item.ownr_fn || ""} ${object.item.ownr_ln || ""} ${ }${object.item.ownr_fn || ""} ${object.item.ownr_ln || ""} ${
object.item.ownr_co_nm || "" object.item.ownr_co_nm || ""
@@ -85,41 +160,19 @@ export function CameraSelectJob({
/> />
</Modal> </Modal>
</Portal> </Portal>
<Button style={{ marginTop: 30 }} onPress={showModal}> <Button mode="outlined" style={{ margin: 8 }} onPress={showModal}>
{cameraJobId {cameraJobId
? `${cameraJob.ro_number ? `${cameraJob.ro_number} - ` : ``}${ ? cameraJobId === "temp"
cameraJob.ownr_fn || "" ? t("mediabrowser.labels.temporarystorage")
} ${cameraJob.ownr_ln || ""} ${cameraJob.ownr_co_nm || ""} - ${ : `${cameraJob.ro_number ? `${cameraJob.ro_number} - ` : ``}${
cameraJob.v_model_yr || "" cameraJob.ownr_fn || ""
} ${cameraJob.v_make_desc || ""} ${cameraJob.v_model_desc || ""}` } ${cameraJob.ownr_ln || ""} ${cameraJob.ownr_co_nm || ""} - ${
cameraJob.v_model_yr || ""
} ${cameraJob.v_make_desc || ""} ${cameraJob.v_model_desc || ""}`
: t("mediabrowser.labels.selectjob")} : t("mediabrowser.labels.selectjob")}
</Button> </Button>
</Provider> </>
); );
// return (
// <View
// style={{
// marginHorizontal: 10,
// }}
// >
// <Picker
// selectedValue={cameraJobId}
// onValueChange={(value, idx) => {
// logImEXEvent("imexmobile_setcamerajobid");
// setCameraJobId(value);
// setCameraJob(data.jobs[idx]);
// }}
// >
// <Picker.Item
// label={t("mediabrowser.labels.selectjob")}
// value={null}
// key="null"
// />
// </Picker>
// </View>
// );
} }
export default connect(mapStateToProps, mapDispatchToProps)(CameraSelectJob); export default connect(mapStateToProps, mapDispatchToProps)(CameraSelectJob);

View File

@@ -1,55 +1,78 @@
import React, { useState } from "react"; import React, { useState, useMemo } from "react";
import { import {
FlatList, FlatList,
Image, Image,
RefreshControl, RefreshControl,
StyleSheet,
Text, Text,
TouchableOpacity, TouchableOpacity,
View, View,
} from "react-native"; } from "react-native";
import env from "../../env";
import { DetermineFileType } from "../../util/document-upload.utility";
import MediaCacheOverlay from "../media-cache-overlay/media-cache-overlay.component"; import MediaCacheOverlay from "../media-cache-overlay/media-cache-overlay.component";
const REACT_APP_CLOUDINARY_IMAGE_ENDPOINT =
"https://res.cloudinary.com/bodyshop/image/upload";
const REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS = "c_fill,f_auto,h_250,w_250";
export default function JobDocumentsComponent({ job, loading, refetch }) { export default function JobDocumentsComponent({ job, loading, refetch }) {
const [previewVisible, setPreviewVisible] = useState(false); const [previewVisible, setPreviewVisible] = useState(false);
const [imgIndex, setImgIndex] = useState(0); const [imgIndex, setImgIndex] = useState(0);
const onRefresh = async () => { const onRefresh = async () => {
return refetch(); return refetch();
}; };
const fullphotos = useMemo(
() =>
job.documents.map((doc) => {
return {
source: {
uri: `${env.REACT_APP_CLOUDINARY_ENDPOINT}/${DetermineFileType(
doc.type
)}/upload/${doc.key}`,
},
};
}),
[job.documents]
);
return ( return (
<View> <View style={{ flex: 1 }}>
<FlatList <FlatList
refreshControl={ refreshControl={
<RefreshControl refreshing={loading} onRefresh={onRefresh} /> <RefreshControl refreshing={loading} onRefresh={onRefresh} />
} }
data={job.documents} data={job.documents}
contentContainerStyle={styles.listContentContainer}
keyExtractor={(item) => item.id}
numColumns={4} numColumns={4}
keyExtractor={(item) => item.id}
renderItem={(object) => ( renderItem={(object) => (
<TouchableOpacity <View
onPress={() => { style={{
setImgIndex(object.index); flex: 1,
setPreviewVisible(true); flexDirection: "column",
margin: 5,
}} }}
> >
<Image <TouchableOpacity
style={{ margin: 5 }} onPress={() => {
source={{ setImgIndex(object.index);
width: 100, setPreviewVisible(true);
height: 100,
uri: `${REACT_APP_CLOUDINARY_IMAGE_ENDPOINT}/${REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS}/${object.item.key}`,
}} }}
/> >
</TouchableOpacity> <Image
source={{
width: 100,
height: 100,
uri: `${
env.REACT_APP_CLOUDINARY_ENDPOINT
}/${DetermineFileType(object.item.type)}/upload/${
env.REACT_APP_CLOUDINARY_THUMB_TRANSFORMATIONS
}/${object.item.key}`,
}}
/>
</TouchableOpacity>
</View>
)} )}
/> />
<Text>{job.documents.length}</Text> <Text>{job.documents.length}</Text>
<MediaCacheOverlay <MediaCacheOverlay
photos={fullphotos}
imgIndex={imgIndex} imgIndex={imgIndex}
setImgIndex={setImgIndex} setImgIndex={setImgIndex}
previewVisible={previewVisible} previewVisible={previewVisible}
@@ -58,22 +81,3 @@ export default function JobDocumentsComponent({ job, loading, refetch }) {
</View> </View>
); );
} }
const styles = StyleSheet.create({
container: {
flex: 1,
},
actions: {
display: "flex",
flexDirection: "row",
justifyContent: "space-evenly",
},
listContentContainer: {
flex: 1,
},
thumbnail: {
width: 10,
height: 10,
backgroundColor: "tomato",
},
});

View File

@@ -2,7 +2,7 @@ import Dinero from "dinero.js";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FlatList, RefreshControl, StyleSheet, Text, View } from "react-native"; import { FlatList, RefreshControl, StyleSheet, Text, View } from "react-native";
import { Card } from "react-native-paper"; import { Card, DataTable } from "react-native-paper";
export default function JobLines({ job, loading, refetch }) { export default function JobLines({ job, loading, refetch }) {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -18,60 +18,64 @@ export default function JobLines({ job, loading, refetch }) {
return ( return (
<View> <View>
<DataTable>
<DataTable.Header>
<DataTable.Title style={{ flex: 4 }}>
{t("jobdetail.labels.lines_desc")}
</DataTable.Title>
<DataTable.Title style={{ flex: 2 }}>
{t("jobdetail.labels.lines_lbr_ty")}
</DataTable.Title>
<DataTable.Title style={{ flex: 1 }}>
{t("jobdetail.labels.lines_lb_hrs")}
</DataTable.Title>
<DataTable.Title style={{ flex: 2 }}>
{t("jobdetail.labels.lines_part_type")}
</DataTable.Title>
<DataTable.Title style={{ flex: 1 }}>
{t("jobdetail.labels.lines_qty")}
</DataTable.Title>
<DataTable.Title style={{ flex: 1 }}>
{t("jobdetail.labels.lines_price")}
</DataTable.Title>
</DataTable.Header>
</DataTable>
<FlatList <FlatList
data={job.joblines} data={job.joblines}
refreshControl={ refreshControl={
<RefreshControl refreshing={loading} onRefresh={onRefresh} /> <RefreshControl refreshing={loading} onRefresh={onRefresh} />
} }
contentContainerStyle={localStyles.listContentContainer}
keyExtractor={(item) => item.id} keyExtractor={(item) => item.id}
renderItem={(object) => ( renderItem={(object) => (
<Card> <DataTable.Row>
<Card.Content style={localStyles.flexRow}> <DataTable.Cell style={{ flex: 4 }}>
<Text style={localStyles.growWithEllipsis}>{`${ {object.item.line_desc}
object.item.line_desc </DataTable.Cell>
}${ <DataTable.Cell style={{ flex: 2 }}>
object.item.part_qty > 1 ? ` x ${object.item.part_qty}` : "" {object.item.mod_lbr_ty &&
}`}</Text> t(`jobdetail.lbr_types.${object.item.mod_lbr_ty}`)}
{object.item.part_type && ( </DataTable.Cell>
<Text style={localStyles.sideMargins}> <DataTable.Cell style={{ flex: 1 }}>
{t(`jobdetail.part_types.${object.item.part_type}`)} {object.item.mod_lb_hrs}
</Text> </DataTable.Cell>
)} <DataTable.Cell style={{ flex: 2 }}>
<Text style={localStyles.sideMargins}> {object.item.part_type &&
{Dinero({ t(`jobdetail.part_types.${object.item.part_type}`)}
amount: Math.round((object.item.act_price || 0) * 100), </DataTable.Cell>
}).toFormat()} <DataTable.Cell style={{ flex: 1 }}>
</Text> {object.item.part_qty}
</Card.Content> </DataTable.Cell>
<Card.Content style={localStyles.flexRow}> <DataTable.Cell style={{ flex: 1 }}>
{object.item.mod_lbr_ty && ( {Dinero({
<Text> amount: Math.round((object.item.act_price || 0) * 100),
{t(`jobdetail.lbr_types.${object.item.mod_lbr_ty}`)} }).toFormat()}
</Text> </DataTable.Cell>
)} </DataTable.Row>
</Card.Content>
</Card>
)} )}
/> />
</View> </View>
); );
} }
const localStyles = StyleSheet.create({ const localStyles = StyleSheet.create({});
listContentContainer: {
flex: 1,
},
flexRow: {
display: "flex",
flexDirection: "row",
justifyContent: "space-between",
},
sideMargins: {
marginLeft: 5,
marginRight: 5,
},
growWithEllipsis: {
flex: 1,
},
});

View File

@@ -4,8 +4,7 @@ import React, { useRef } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Animated } from "react-native"; import { Animated } from "react-native";
import { TouchableOpacity } from "react-native-gesture-handler"; import { TouchableOpacity } from "react-native-gesture-handler";
import Swipeable from "react-native-gesture-handler/Swipeable"; import { Button, List, Title } from "react-native-paper";
import { List } from "react-native-paper";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import { logImEXEvent } from "../../firebase/firebase.utils"; import { logImEXEvent } from "../../firebase/firebase.utils";
@@ -60,21 +59,35 @@ export function JobListItem({ setCameraJob, setCameraJobId, item }) {
}; };
return ( return (
<Swipeable <TouchableOpacity onPress={onPress}>
ref={_swipeableRow}
renderRightActions={RenderRightAction}
shouldCancelWhenOutside
>
<List.Item <List.Item
onPress={onPress} title={<Title>{item.ro_number || t("general.labels.na")}</Title>}
title={item.ro_number || t("general.labels.na")}
description={`${item.ownr_fn || ""} ${item.ownr_ln || ""} ${ description={`${item.ownr_fn || ""} ${item.ownr_ln || ""} ${
item.ownr_co_nm || "" item.ownr_co_nm || ""
} - ${item.v_model_yr || ""} ${item.v_make_desc || ""} ${ } - ${item.v_model_yr || ""} ${item.v_make_desc || ""} ${
item.v_model_desc || "" item.v_model_desc || ""
}`} }`}
right={({ style }) => (
<Button
style={style}
onPress={() => {
logImEXEvent("imexmobile_setcamerajobid_swipe");
setCameraJobId(item.id);
setCameraJob(item);
navigation.navigate("MediaBrowserTab");
_swipeableRow.current.close();
}}
>
<Ionicons
style={style}
name="ios-add"
size={32}
color="dodgerblue"
/>
</Button>
)}
/> />
</Swipeable> </TouchableOpacity>
); );
} }

View File

@@ -5,7 +5,7 @@ import { Text, View } from "react-native";
import { Card } from "react-native-paper"; import { Card } from "react-native-paper";
export default function NoteListItem({ item }) { export default function NoteListItem({ item }) {
return ( return (
<Card> <Card style={{ margin: 8 }}>
<Card.Content> <Card.Content>
<View style={{ display: "flex", flex: 1 }}> <View style={{ display: "flex", flex: 1 }}>
<Text>{item.text}</Text> <Text>{item.text}</Text>

View File

@@ -1,8 +1,8 @@
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FlatList, RefreshControl, Text } from "react-native"; import { FlatList, RefreshControl, Text } from "react-native";
import JobNotesItem from "../job-notes-item/job-notes-item.component";
import { Card } from "react-native-paper"; import { Card } from "react-native-paper";
import JobNotesItem from "../job-notes-item/job-notes-item.component";
export default function JobNotes({ job, loading, refetch }) { export default function JobNotes({ job, loading, refetch }) {
const { t } = useTranslation(); const { t } = useTranslation();
if (!job) { if (!job) {
@@ -14,6 +14,7 @@ export default function JobNotes({ job, loading, refetch }) {
const onRefresh = async () => { const onRefresh = async () => {
return refetch(); return refetch();
}; };
if (job.notes.length === 0) if (job.notes.length === 0)
return ( return (
<Card> <Card>
@@ -31,7 +32,6 @@ export default function JobNotes({ job, loading, refetch }) {
style={{ flex: 1 }} style={{ flex: 1 }}
data={job.notes} data={job.notes}
renderItem={(object) => <JobNotesItem item={object.item} />} renderItem={(object) => <JobNotesItem item={object.item} />}
//ItemSeparatorComponent={FlatListItemSeparator}
/> />
); );
} }

View File

@@ -1,14 +1,16 @@
import { Card } from "react-native-paper";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { import {
RefreshControl, RefreshControl,
StyleSheet,
ScrollView, ScrollView,
StyleSheet,
Text, Text,
View, View,
} from "react-native"; } from "react-native";
import { Card, Headline, Subheading } from "react-native-paper";
import DataLabelComponent from "../data-label/data-label.component"; import DataLabelComponent from "../data-label/data-label.component";
import StyleRepeater from "../style-repeater/style-repeater";
import styles from "../styles";
export default function JobTombstone({ job, loading, refetch }) { export default function JobTombstone({ job, loading, refetch }) {
const { t } = useTranslation(); const { t } = useTranslation();
@@ -23,114 +25,121 @@ export default function JobTombstone({ job, loading, refetch }) {
return ( return (
<ScrollView <ScrollView
padder style={styles.cardBackground}
refreshControl={ refreshControl={
<RefreshControl refreshing={loading} onRefresh={onRefresh} /> <RefreshControl refreshing={loading} onRefresh={onRefresh} />
} }
> >
<Card> <StyleRepeater childStyle={{ margin: 4 }}>
<Card.Content bordered style={localStyles.status}> <Card>
<Text>{job.status}</Text> <Card.Title title={t("jobdetail.labels.jobinfo")} />
</Card.Content> <Card.Content>
{job.inproduction && ( <Headline>{job.status}</Headline>
<Card.Content bordered style={localStyles.inproduction}> {job.inproduction && (
<Text>{t("objects.jobs.labels.inproduction")}</Text> <Subheading>{t("objects.jobs.labels.inproduction")}</Subheading>
)}
{job.inproduction &&
job.production_vars &&
!!job.production_vars.note && (
<Subheading>{job.production_vars.note}</Subheading>
)}
</Card.Content> </Card.Content>
)} </Card>
{job.inproduction && job.production_vars && !!job.production_vars.note && (
<Card.Content bordered style={localStyles.inproduction}> <Card>
<Text>{job.production_vars.note}</Text> <Card.Title title={t("jobdetail.labels.claiminformation")} />
<Card.Content style={localStyles.twoColumnCard}>
<View style={localStyles.twoColumnCardColumn}>
<DataLabelComponent
label={t("objects.jobs.fields.owner")}
content={`${job.ownr_fn || ""} ${job.ownr_ln || ""} ${
job.ownr_co_nm || ""
}`}
/>
<DataLabelComponent
label={t("objects.jobs.fields.vehicle")}
content={`${job.v_model_yr || ""} ${job.v_make_desc || ""} ${
job.v_model_desc || ""
}`}
/>
</View>
<View style={localStyles.twoColumnCardColumn}>
<DataLabelComponent
label={t("objects.jobs.fields.ins_co_nm")}
content={job.ins_co_nm}
/>
<DataLabelComponent
label={t("objects.jobs.fields.clm_no")}
content={job.clm_no}
/>
</View>
</Card.Content> </Card.Content>
)} </Card>
</Card> <Card>
<Card> <Card.Title title={t("jobdetail.labels.employeeassignments")} />
<Card.Content bordered style={localStyles.status}> <Card.Content>
<Text>{t("jobdetail.labels.claiminformation")}</Text> <DataLabelComponent
</Card.Content> label={t("objects.jobs.fields.employee_body")}
<View> content={`${
<DataLabelComponent (job.employee_body_rel && job.employee_body_rel.first_name) ||
label={t("objects.jobs.fields.owner")} ""
content={`${job.ownr_fn || ""} ${job.ownr_ln || ""} ${ } ${
job.ownr_co_nm || "" (job.employee_body_rel && job.employee_body_rel.last_name) || ""
}`} }`}
/> />
<DataLabelComponent <DataLabelComponent
label={t("objects.jobs.fields.vehicle")} label={t("objects.jobs.fields.employee_prep")}
content={`${job.v_model_yr || ""} ${job.v_make_desc || ""} ${ content={`${
job.v_model_desc || "" (job.employee_prep_rel && job.employee_prep_rel.first_name) ||
}`} ""
/> } ${
<DataLabelComponent (job.employee_prep_rel && job.employee_prep_rel.last_name) || ""
label={t("objects.jobs.fields.ins_co_nm")} }`}
content={job.ins_co_nm} />
/> <DataLabelComponent
<DataLabelComponent label={t("objects.jobs.fields.employee_refinish")}
label={t("objects.jobs.fields.clm_no")} content={`${
content={job.clm_no} (job.employee_refinish_rel &&
/> job.employee_refinish_rel.first_name) ||
</View> ""
</Card> } ${
<Card> (job.employee_refinish_rel &&
<Card.Content bordered style={localStyles.status}> job.employee_refinish_rel.last_name) ||
<Text>{t("jobdetail.labels.employeeassignments")}</Text> ""
</Card.Content> }`}
<View> />
<DataLabelComponent </Card.Content>
label={t("objects.jobs.fields.employee_body")} </Card>
content={`${ <Card>
(job.employee_body_rel && job.employee_body_rel.first_name) || "" <Card.Title title={t("jobdetail.labels.dates")} />
} ${ <Card.Content style={localStyles.twoColumnCard}>
(job.employee_body_rel && job.employee_body_rel.last_name) || "" <View style={localStyles.twoColumnCardColumn}>
}`} <DataLabelComponent
/> label={t("objects.jobs.fields.scheduled_in")}
<DataLabelComponent content={job.scheduled_in}
label={t("objects.jobs.fields.employee_prep")} dateTime
content={`${ />
(job.employee_prep_rel && job.employee_prep_rel.first_name) || "" <DataLabelComponent
} ${ label={t("objects.jobs.fields.actual_in")}
(job.employee_prep_rel && job.employee_prep_rel.last_name) || "" content={job.actual_in}
}`} dateTime
/> />
<DataLabelComponent </View>
label={t("objects.jobs.fields.employee_refinish")} <View style={localStyles.twoColumnCardColumn}>
content={`${ <DataLabelComponent
(job.employee_refinish_rel && label={t("objects.jobs.fields.scheduled_completion")}
job.employee_refinish_rel.first_name) || content={job.scheduled_completion}
"" dateTime
} ${ />
(job.employee_refinish_rel && <DataLabelComponent
job.employee_refinish_rel.last_name) || label={t("objects.jobs.fields.scheduled_delivery")}
"" content={job.scheduled_delivery}
}`} dateTime
/> />
</View> </View>
</Card> </Card.Content>
<Card style={localStyles.twoColumnCard}> </Card>
<View style={localStyles.twoColumnCardColumn}> </StyleRepeater>
<DataLabelComponent
label={t("objects.jobs.fields.scheduled_in")}
content={job.scheduled_in}
dateTime
/>
<DataLabelComponent
label={t("objects.jobs.fields.actual_in")}
content={job.actual_in}
dateTime
/>
</View>
<View style={localStyles.twoColumnCardColumn}>
<DataLabelComponent
label={t("objects.jobs.fields.scheduled_completion")}
content={job.scheduled_completion}
dateTime
/>
<DataLabelComponent
label={t("objects.jobs.fields.scheduled_delivery")}
content={job.scheduled_delivery}
dateTime
/>
</View>
</Card>
</ScrollView> </ScrollView>
); );
} }
@@ -144,7 +153,6 @@ const localStyles = StyleSheet.create({
justifyContent: "center", justifyContent: "center",
}, },
inproduction: { inproduction: {
backgroundColor: "tomato",
textAlign: "center", textAlign: "center",
flexDirection: "row", flexDirection: "row",
justifyContent: "center", justifyContent: "center",

View File

@@ -1,84 +1,23 @@
import React from "react"; import React from "react";
import { Alert, Modal, StyleSheet, Text, Button, View } from "react-native"; import { Modal } from "react-native";
import ImageViewer from "react-native-image-zoom-viewer"; import Gallery from "react-native-image-gallery";
import { connect } from "react-redux";
import { createStructuredSelector } from "reselect";
import { removePhotos } from "../../redux/photos/photos.actions";
import { selectPhotos } from "../../redux/photos/photos.selectors";
const mapStateToProps = createStructuredSelector({ export default function MediaCacheOverlay({
photos: selectPhotos,
});
const mapDispatchToProps = (dispatch) => ({
removePhotos: (ids) => dispatch(removePhotos(ids)),
});
export function MediaCacheOverlay({
photos, photos,
removePhotos,
previewVisible, previewVisible,
setPreviewVisible, setPreviewVisible,
imgIndex, imgIndex,
setImgIndex, setImgIndex,
}) { }) {
console.log("photos :>> ", photos);
return ( return (
<Modal <Modal
animationType="slide" onDismiss={() => setPreviewVisible(false)}
onRequestClose={() => { onRequestClose={() => setPreviewVisible(false)}
Alert.alert("Modal has been closed.");
}}
visible={previewVisible} visible={previewVisible}
transparent={true} transparent={false}
> >
<ImageViewer <Gallery initialPage={imgIndex} style={{ flex: 1 }} images={photos} />
onCancel={() => setPreviewVisible(false)}
index={imgIndex}
onChange={(index) => setImgIndex(index)}
style={{ display: "flex" }}
renderFooter={(index) => (
<View
style={{
marginleft: "auto",
backgroundColor: "tomato",
}}
>
<Text>{index} This is the thing.</Text>
<Button
onPress={() => {
removePhotos([photos[index].id]);
}}
>
<Text>Delete</Text>
</Button>
</View>
)}
enableSwipeDown
enablePreload
imageUrls={photos.map((p) => {
return { url: p.uri };
})}
/>
</Modal> </Modal>
); );
} }
const styles = StyleSheet.create({
container: {
flex: 1,
},
actions: {
display: "flex",
flexDirection: "row",
justifyContent: "space-evenly",
},
listContentContainer: {
flex: 1,
},
thumbnail: {
width: 10,
height: 10,
backgroundColor: "tomato",
},
});
export default connect(mapStateToProps, mapDispatchToProps)(MediaCacheOverlay);

View File

@@ -2,7 +2,7 @@ import { useQuery } from "@apollo/client";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { useWindowDimensions } from "react-native"; import { useWindowDimensions } from "react-native";
import { SceneMap, TabView } from "react-native-tab-view"; import { SceneMap, TabView, TabBar } from "react-native-tab-view";
import { GET_JOB_BY_PK } from "../../graphql/jobs.queries"; import { GET_JOB_BY_PK } from "../../graphql/jobs.queries";
import ErrorDisplay from "../error-display/error-display.component"; import ErrorDisplay from "../error-display/error-display.component";
import JobDocuments from "../job-documents/job-documents.component"; import JobDocuments from "../job-documents/job-documents.component";
@@ -24,6 +24,14 @@ export default function ScreenJobDetail({ route }) {
skip: !jobId, skip: !jobId,
}); });
const renderTabBar = (props) => (
<TabBar
{...props}
indicatorStyle={{ backgroundColor: "white" }}
style={{ backgroundColor: "dodgerblue" }}
/>
);
const renderScene = SceneMap({ const renderScene = SceneMap({
job: () => job: () =>
JobTombstone({ JobTombstone({
@@ -68,6 +76,7 @@ export default function ScreenJobDetail({ route }) {
renderScene={renderScene} renderScene={renderScene}
onIndexChange={setIndex} onIndexChange={setIndex}
initialLayout={{ width: layout.width }} initialLayout={{ width: layout.width }}
renderTabBar={renderTabBar}
/> />
); );
} }

View File

@@ -64,7 +64,6 @@ export function ImageBrowserScreen({
} }
const onDone = async (data) => { const onDone = async (data) => {
console.log("Assets :>> ", data);
logImEXEvent("imexmobile_upload_documents", { count: data.length }); logImEXEvent("imexmobile_upload_documents", { count: data.length });
const actions = []; const actions = [];
data.forEach(function (p) { data.forEach(function (p) {

View File

@@ -1,7 +1,8 @@
import { Formik } from "formik"; import { Formik } from "formik";
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { ActivityIndicator, Image, StyleSheet, View, Text } from "react-native"; import { Image, StyleSheet, Text, View } from "react-native";
import { Button, TextInput, Title } from "react-native-paper";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import Logo from "../../assets/logo192.png"; import Logo from "../../assets/logo192.png";
@@ -11,8 +12,6 @@ import {
selectSigningIn, selectSigningIn,
} from "../../redux/user/user.selectors"; } from "../../redux/user/user.selectors";
import SignInErrorAlertComponent from "../sign-in-error-alert/sign-in-error-alert.component"; import SignInErrorAlertComponent from "../sign-in-error-alert/sign-in-error-alert.component";
import styles from "../styles";
import { TextInput, Button, Subheading } from "react-native-paper";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
currentUser: selectCurrentUser, currentUser: selectCurrentUser,
@@ -33,41 +32,46 @@ export function SignIn({ emailSignInStart, signingIn }) {
}; };
return ( return (
<View <View style={localStyles.content}>
scrollEnabled={false} <View
contentContainerStyle={styles.contentContainer__centered} style={{
style={localStyles.content} display: "flex",
>
<View style={styles.evenlySpacedRow}> flexDirection: "row",
alignItems: "center",
justifyContent: "space-evenly",
}}
>
<Image style={localStyles.logo} source={Logo} /> <Image style={localStyles.logo} source={Logo} />
<Text>{t("app.title")}</Text> <Title>{t("app.title")}</Title>
</View> </View>
<Formik initialValues={{ email: "", password: "" }} onSubmit={formSubmit}> <Formik initialValues={{ email: "", password: "" }} onSubmit={formSubmit}>
{({ handleChange, handleBlur, handleSubmit, values }) => ( {({ handleChange, handleBlur, handleSubmit, values }) => (
<View> <View>
<View> <TextInput
<Subheading>{t("signin.fields.email")}</Subheading> label={t("signin.fields.email")}
<TextInput mode="outlined"
autoCapitalize="none" autoCapitalize="none"
keyboardType="email-address" keyboardType="email-address"
onChangeText={handleChange("email")} onChangeText={handleChange("email")}
onBlur={handleBlur("email")} onBlur={handleBlur("email")}
value={values.email} value={values.email}
/> style={[localStyles.input]}
</View> />
<View>
<Subheading>{t("signin.fields.password")}</Subheading> <TextInput
<TextInput label={t("signin.fields.password")}
secureTextEntry={true} mode="outlined"
onChangeText={handleChange("password")} secureTextEntry={true}
onBlur={handleBlur("password")} onChangeText={handleChange("password")}
value={values.password} onBlur={handleBlur("password")}
/> value={values.password}
</View> style={[localStyles.input]}
/>
<SignInErrorAlertComponent /> <SignInErrorAlertComponent />
<Button full onPress={handleSubmit}> <Button mode="outlined" loading={signingIn} onPress={handleSubmit}>
<Text>{t("signin.actions.signin")}</Text> <Text>{t("signin.actions.signin")}</Text>
{signingIn ? <ActivityIndicator size="large" /> : null}
</Button> </Button>
</View> </View>
)} )}
@@ -78,9 +82,13 @@ export function SignIn({ emailSignInStart, signingIn }) {
const localStyles = StyleSheet.create({ const localStyles = StyleSheet.create({
content: { content: {
paddingBottom: 200, display: "flex",
flex: 1,
}, },
logo: { width: 100, height: 100 }, logo: { width: 100, height: 100 },
input: {
margin: 12,
},
}); });
export default connect(mapStateToProps, mapDispatchToProps)(SignIn); export default connect(mapStateToProps, mapDispatchToProps)(SignIn);

View File

@@ -1,29 +1,35 @@
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { Image, StyleSheet, View } from "react-native"; import { ActivityIndicator, Image, StyleSheet, View } from "react-native";
import { BarIndicator } from "react-native-indicators";
import { Title } from "react-native-paper"; import { Title } from "react-native-paper";
import Logo from "../../assets/logo192.png"; import Logo from "../../assets/logo192.png";
import styles from "../styles";
export default function ScreenSplash() { export default function ScreenSplash() {
const { t } = useTranslation(); const { t } = useTranslation();
return ( return (
<View <View style={[localStyles.container]}>
contentContainerStyle={[ <View style={[localStyles.logoContainer]}>
styles.contentContainer__centered, <Image style={localStyles.logo} source={Logo} />
localStyles.middleAlign, <Title>{t("app.title")}</Title>
]} </View>
>
<Image style={localStyles.logo} source={Logo} /> <ActivityIndicator color="dodgerblue" size="large" />
<Title>{t("app.title")}</Title>
<BarIndicator count={5} color="dodgerblue" />
</View> </View>
); );
} }
const localStyles = StyleSheet.create({ const localStyles = StyleSheet.create({
middleAlign: { container: {
display: "flex",
flex: 1,
flexDirection: "column",
alignContent: "center",
justifyContent: "center",
},
logoContainer: {
display: "flex",
flexDirection: "column",
alignItems: "center", alignItems: "center",
}, },
logo: { width: 100, height: 100, margin: 20 }, logo: { width: 175, height: 175, margin: 20 },
}); });

View File

@@ -0,0 +1,13 @@
import React from "react";
export default function StyleRepeater({ childStyle, children }) {
return (
<>
{React.Children.map(children, (child) =>
React.cloneElement(child, {
style: [child.props.style, childStyle],
})
)}
</>
);
}

View File

@@ -1,30 +1,12 @@
import { StyleSheet } from "react-native"; import { StyleSheet } from "react-native";
const cardBackgroundColor = "gainsboro";
export default StyleSheet.create({ export default StyleSheet.create({
contentContainer__centered: { cardBackground: {
justifyContent: "center", padding: 5,
backgroundColor: cardBackgroundColor,
display: "flex",
flex: 1, flex: 1,
}, },
evenlySpacedRow: {
flexDirection: "row",
justifyContent: "space-evenly",
alignItems: "center",
},
swipe_view: {
flex: 1,
alignItems: "center",
justifyContent: "center",
width: 100,
// marginTop: 5,
//marginBottom: 5,
},
swipe_view_blue: {
backgroundColor: "dodgerblue",
},
swipe_text: {
textAlign: "center",
color: "white",
},
}); });

View File

@@ -1,5 +1,5 @@
import { Ionicons } from "@expo/vector-icons"; import { Ionicons } from "@expo/vector-icons";
import React from "react"; import React, { useMemo } from "react";
import { import {
ScrollView, ScrollView,
StyleSheet, StyleSheet,
@@ -10,10 +10,15 @@ import {
import * as Progress from "react-native-progress"; import * as Progress from "react-native-progress";
import _ from "lodash"; import _ from "lodash";
export default function UploadProgress({ uploads, setUploads }) { export default function UploadProgress({ uploads, setUploads }) {
const uploadKeys = useMemo(() => {
if (uploads) return Object.keys(uploads);
return [];
}, [uploads]);
return ( return (
<View style={styles.container}> <View style={styles.container}>
<ScrollView> <ScrollView>
{Object.keys(uploads).map((key) => ( {uploadKeys.map((key) => (
<View key={key} style={styles.progressItem}> <View key={key} style={styles.progressItem}>
<Text style={styles.progressText}>{key}</Text> <Text style={styles.progressText}>{key}</Text>
<View style={styles.progressBarContainer}> <View style={styles.progressBarContainer}>

1
env.js
View File

@@ -5,6 +5,7 @@ export const prodUrl = "https://someapp.herokuapp.com";
const ENV = { const ENV = {
dev: { dev: {
API_URL: "https://api.imex.online", API_URL: "https://api.imex.online",
REACT_APP_CLOUDINARY_ENDPOINT_API: REACT_APP_CLOUDINARY_ENDPOINT_API:
"https://api.cloudinary.com/v1_1/bodyshop", "https://api.cloudinary.com/v1_1/bodyshop",
REACT_APP_CLOUDINARY_ENDPOINT: "https://res.cloudinary.com/bodyshop", REACT_APP_CLOUDINARY_ENDPOINT: "https://res.cloudinary.com/bodyshop",

View File

@@ -274,6 +274,7 @@ export const GET_JOB_BY_PK = gql`
name name
key key
created_at created_at
type
} }
} }
} }

71
package-lock.json generated
View File

@@ -42,7 +42,7 @@
"react-native": "https://github.com/expo/react-native/archive/sdk-40.0.0.tar.gz", "react-native": "https://github.com/expo/react-native/archive/sdk-40.0.0.tar.gz",
"react-native-easy-grid": "^0.2.2", "react-native-easy-grid": "^0.2.2",
"react-native-gesture-handler": "~1.8.0", "react-native-gesture-handler": "~1.8.0",
"react-native-image-zoom-viewer": "^3.0.1", "react-native-image-gallery": "^2.1.5",
"react-native-indicators": "^0.17.0", "react-native-indicators": "^0.17.0",
"react-native-pager-view": "^5.1.0", "react-native-pager-view": "^5.1.0",
"react-native-paper": "^4.7.2", "react-native-paper": "^4.7.2",
@@ -13001,6 +13001,15 @@
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/react-mixin": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/react-mixin/-/react-mixin-3.1.1.tgz",
"integrity": "sha512-z9fZ0aCRDjlgxLdMeWkJ9TwhmVLhQ09r8RFpin/cEPA2T6jsb7YHNWcIe0Oii+hhJNyMymdy91CSya5mRkuCkg==",
"dependencies": {
"object-assign": "^4.0.1",
"smart-mixin": "^2.0.0"
}
},
"node_modules/react-native": { "node_modules/react-native": {
"version": "0.63.2", "version": "0.63.2",
"license": "MIT", "license": "MIT",
@@ -13063,23 +13072,14 @@
"prop-types": "^15.7.2" "prop-types": "^15.7.2"
} }
}, },
"node_modules/react-native-image-pan-zoom": { "node_modules/react-native-image-gallery": {
"version": "2.1.12", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/react-native-image-pan-zoom/-/react-native-image-pan-zoom-2.1.12.tgz", "resolved": "https://registry.npmjs.org/react-native-image-gallery/-/react-native-image-gallery-2.1.5.tgz",
"integrity": "sha512-BF66XeP6dzuANsPmmFsJshM2Jyh/Mo1t8FsGc1L9Q9/sVP8MJULDabB1hms+eAoqgtyhMr5BuXV3E1hJ5U5H6Q==", "integrity": "sha512-xC7nuPu4GUH0da6byofQ10LjtqlKj+VaLc0NHBJmeMHVvdvmRvFEO6UOq0Q0m/ePx3OQiPTNwGbf5BSPJEKa0w==",
"license": "ISC",
"peerDependencies": {
"react": "*",
"react-native": "*"
}
},
"node_modules/react-native-image-zoom-viewer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/react-native-image-zoom-viewer/-/react-native-image-zoom-viewer-3.0.1.tgz",
"integrity": "sha512-la6s5DNSuq4GCRLsi5CZ29FPjgTpdCuGIRdO5T9rUrAtxrlpBPhhSnHrbmPVxsdtOUvxHacTh2Gfa9+RraMZQA==",
"license": "MIT",
"dependencies": { "dependencies": {
"react-native-image-pan-zoom": "^2.1.12" "prop-types": "^15.6.0",
"react-mixin": "^3.0.5",
"react-timer-mixin": "^0.13.3"
}, },
"peerDependencies": { "peerDependencies": {
"react": "*", "react": "*",
@@ -14223,6 +14223,11 @@
"node": ">=8.0.0" "node": ">=8.0.0"
} }
}, },
"node_modules/smart-mixin": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/smart-mixin/-/smart-mixin-2.0.0.tgz",
"integrity": "sha1-o0oQVeMqdbMNK048oyPcmctT9Dc="
},
"node_modules/snapdragon": { "node_modules/snapdragon": {
"version": "0.8.2", "version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
@@ -25256,6 +25261,15 @@
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
}, },
"react-mixin": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/react-mixin/-/react-mixin-3.1.1.tgz",
"integrity": "sha512-z9fZ0aCRDjlgxLdMeWkJ9TwhmVLhQ09r8RFpin/cEPA2T6jsb7YHNWcIe0Oii+hhJNyMymdy91CSya5mRkuCkg==",
"requires": {
"object-assign": "^4.0.1",
"smart-mixin": "^2.0.0"
}
},
"react-native": { "react-native": {
"version": "0.63.2", "version": "0.63.2",
"requires": { "requires": {
@@ -25317,18 +25331,14 @@
"prop-types": "^15.7.2" "prop-types": "^15.7.2"
} }
}, },
"react-native-image-pan-zoom": { "react-native-image-gallery": {
"version": "2.1.12", "version": "2.1.5",
"resolved": "https://registry.npmjs.org/react-native-image-pan-zoom/-/react-native-image-pan-zoom-2.1.12.tgz", "resolved": "https://registry.npmjs.org/react-native-image-gallery/-/react-native-image-gallery-2.1.5.tgz",
"integrity": "sha512-BF66XeP6dzuANsPmmFsJshM2Jyh/Mo1t8FsGc1L9Q9/sVP8MJULDabB1hms+eAoqgtyhMr5BuXV3E1hJ5U5H6Q==", "integrity": "sha512-xC7nuPu4GUH0da6byofQ10LjtqlKj+VaLc0NHBJmeMHVvdvmRvFEO6UOq0Q0m/ePx3OQiPTNwGbf5BSPJEKa0w==",
"requires": {}
},
"react-native-image-zoom-viewer": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/react-native-image-zoom-viewer/-/react-native-image-zoom-viewer-3.0.1.tgz",
"integrity": "sha512-la6s5DNSuq4GCRLsi5CZ29FPjgTpdCuGIRdO5T9rUrAtxrlpBPhhSnHrbmPVxsdtOUvxHacTh2Gfa9+RraMZQA==",
"requires": { "requires": {
"react-native-image-pan-zoom": "^2.1.12" "prop-types": "^15.6.0",
"react-mixin": "^3.0.5",
"react-timer-mixin": "^0.13.3"
} }
}, },
"react-native-indicators": { "react-native-indicators": {
@@ -26146,6 +26156,11 @@
"resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.7.tgz", "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.4.7.tgz",
"integrity": "sha512-tf+h5W1IrjNm/9rKKj0JU2MDMruiopx0jjVA5zCdBtcGjfp0+c5rHw/zADLC3IeKlGHtVbHtpfzvYA0OYT+HKg==" "integrity": "sha512-tf+h5W1IrjNm/9rKKj0JU2MDMruiopx0jjVA5zCdBtcGjfp0+c5rHw/zADLC3IeKlGHtVbHtpfzvYA0OYT+HKg=="
}, },
"smart-mixin": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/smart-mixin/-/smart-mixin-2.0.0.tgz",
"integrity": "sha1-o0oQVeMqdbMNK048oyPcmctT9Dc="
},
"snapdragon": { "snapdragon": {
"version": "0.8.2", "version": "0.8.2",
"resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",

View File

@@ -45,7 +45,7 @@
"react-native": "https://github.com/expo/react-native/archive/sdk-40.0.0.tar.gz", "react-native": "https://github.com/expo/react-native/archive/sdk-40.0.0.tar.gz",
"react-native-easy-grid": "^0.2.2", "react-native-easy-grid": "^0.2.2",
"react-native-gesture-handler": "~1.8.0", "react-native-gesture-handler": "~1.8.0",
"react-native-image-zoom-viewer": "^3.0.1", "react-native-image-gallery": "^2.1.5",
"react-native-indicators": "^0.17.0", "react-native-indicators": "^0.17.0",
"react-native-pager-view": "^5.1.0", "react-native-pager-view": "^5.1.0",
"react-native-paper": "^4.7.2", "react-native-paper": "^4.7.2",

View File

@@ -19,10 +19,18 @@
"jobdetail": { "jobdetail": {
"labels": { "labels": {
"claiminformation": "Claim Information", "claiminformation": "Claim Information",
"documents": "Documents", "dates": "Dates",
"documents": "Docs",
"employeeassignments": "Employee Assignments", "employeeassignments": "Employee Assignments",
"job": "Job", "job": "Job",
"jobinfo": "Job Information",
"lines": "Lines", "lines": "Lines",
"lines_desc": "Desc.",
"lines_lb_hrs": "Hrs",
"lines_lbr_ty": "Lbr. Ty.",
"lines_part_type": "Part Ty.",
"lines_price": "$",
"lines_qty": "Qty.",
"nojobnotes": "There are no notes.", "nojobnotes": "There are no notes.",
"notes": "Notes" "notes": "Notes"
}, },

View File

@@ -19,10 +19,18 @@
"jobdetail": { "jobdetail": {
"labels": { "labels": {
"claiminformation": "", "claiminformation": "",
"dates": "",
"documents": "", "documents": "",
"employeeassignments": "", "employeeassignments": "",
"job": "", "job": "",
"jobinfo": "",
"lines": "", "lines": "",
"lines_desc": "",
"lines_lb_hrs": "",
"lines_lbr_ty": "",
"lines_part_type": "",
"lines_price": "",
"lines_qty": "",
"nojobnotes": "", "nojobnotes": "",
"notes": "" "notes": ""
}, },

View File

@@ -19,10 +19,18 @@
"jobdetail": { "jobdetail": {
"labels": { "labels": {
"claiminformation": "", "claiminformation": "",
"dates": "",
"documents": "", "documents": "",
"employeeassignments": "", "employeeassignments": "",
"job": "", "job": "",
"jobinfo": "",
"lines": "", "lines": "",
"lines_desc": "",
"lines_lb_hrs": "",
"lines_lbr_ty": "",
"lines_part_type": "",
"lines_price": "",
"lines_qty": "",
"nojobnotes": "", "nojobnotes": "",
"notes": "" "notes": ""
}, },

View File

@@ -181,7 +181,6 @@ export const uploadToCloudinary = async (
}; };
export function DetermineFileType(filetype) { export function DetermineFileType(filetype) {
console.log("Checking Type", filetype, filetype.startsWith("video"));
if (!filetype) return "auto"; if (!filetype) return "auto";
else if (filetype.startsWith("image")) return "image"; else if (filetype.startsWith("image")) return "image";
else if (filetype.startsWith("video")) return "video"; else if (filetype.startsWith("video")) return "video";

View File

@@ -7338,6 +7338,14 @@
"resolved" "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz" "resolved" "https://registry.npmjs.org/react-is/-/react-is-17.0.1.tgz"
"version" "17.0.1" "version" "17.0.1"
"react-mixin@^3.0.5":
"integrity" "sha512-z9fZ0aCRDjlgxLdMeWkJ9TwhmVLhQ09r8RFpin/cEPA2T6jsb7YHNWcIe0Oii+hhJNyMymdy91CSya5mRkuCkg=="
"resolved" "https://registry.npmjs.org/react-mixin/-/react-mixin-3.1.1.tgz"
"version" "3.1.1"
dependencies:
"object-assign" "^4.0.1"
"smart-mixin" "^2.0.0"
"react-native-easy-grid@^0.2.2": "react-native-easy-grid@^0.2.2":
"integrity" "sha512-MlYrNIldnEMKn6TVatQN1P64GoVlwGIuz+8ncdfJ0Wq/xtzUkQwlil8Uksyp7MhKfENE09MQnGNcba6Mx3oSAA==" "integrity" "sha512-MlYrNIldnEMKn6TVatQN1P64GoVlwGIuz+8ncdfJ0Wq/xtzUkQwlil8Uksyp7MhKfENE09MQnGNcba6Mx3oSAA=="
"resolved" "https://registry.npmjs.org/react-native-easy-grid/-/react-native-easy-grid-0.2.2.tgz" "resolved" "https://registry.npmjs.org/react-native-easy-grid/-/react-native-easy-grid-0.2.2.tgz"
@@ -7355,17 +7363,14 @@
"invariant" "^2.2.4" "invariant" "^2.2.4"
"prop-types" "^15.7.2" "prop-types" "^15.7.2"
"react-native-image-pan-zoom@^2.1.12": "react-native-image-gallery@^2.1.5":
"integrity" "sha512-BF66XeP6dzuANsPmmFsJshM2Jyh/Mo1t8FsGc1L9Q9/sVP8MJULDabB1hms+eAoqgtyhMr5BuXV3E1hJ5U5H6Q==" "integrity" "sha512-xC7nuPu4GUH0da6byofQ10LjtqlKj+VaLc0NHBJmeMHVvdvmRvFEO6UOq0Q0m/ePx3OQiPTNwGbf5BSPJEKa0w=="
"resolved" "https://registry.npmjs.org/react-native-image-pan-zoom/-/react-native-image-pan-zoom-2.1.12.tgz" "resolved" "https://registry.npmjs.org/react-native-image-gallery/-/react-native-image-gallery-2.1.5.tgz"
"version" "2.1.12" "version" "2.1.5"
"react-native-image-zoom-viewer@^3.0.1":
"integrity" "sha512-la6s5DNSuq4GCRLsi5CZ29FPjgTpdCuGIRdO5T9rUrAtxrlpBPhhSnHrbmPVxsdtOUvxHacTh2Gfa9+RraMZQA=="
"resolved" "https://registry.npmjs.org/react-native-image-zoom-viewer/-/react-native-image-zoom-viewer-3.0.1.tgz"
"version" "3.0.1"
dependencies: dependencies:
"react-native-image-pan-zoom" "^2.1.12" "prop-types" "^15.6.0"
"react-mixin" "^3.0.5"
"react-timer-mixin" "^0.13.3"
"react-native-indicators@^0.17.0": "react-native-indicators@^0.17.0":
"integrity" "sha512-s23em477GHGxWeGczWrixScAZD6tQU4mx1fttlrwhEGKOxhBgp55Kh3RoD9Wj4yna4e5W35xQNoPqoJAT6QW5A==" "integrity" "sha512-s23em477GHGxWeGczWrixScAZD6tQU4mx1fttlrwhEGKOxhBgp55Kh3RoD9Wj4yna4e5W35xQNoPqoJAT6QW5A=="
@@ -7499,7 +7504,7 @@
"resolved" "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz" "resolved" "https://registry.npmjs.org/react-refresh/-/react-refresh-0.4.3.tgz"
"version" "0.4.3" "version" "0.4.3"
"react-timer-mixin@^0.13.4": "react-timer-mixin@^0.13.3", "react-timer-mixin@^0.13.4":
"integrity" "sha512-4+ow23tp/Tv7hBM5Az5/Be/eKKF7DIvJ09voz5LyHGQaqqz9WV8YMs31eFvcYQs7d451LSg7kDJV70XYN/Ug/Q==" "integrity" "sha512-4+ow23tp/Tv7hBM5Az5/Be/eKKF7DIvJ09voz5LyHGQaqqz9WV8YMs31eFvcYQs7d451LSg7kDJV70XYN/Ug/Q=="
"resolved" "https://registry.npmjs.org/react-timer-mixin/-/react-timer-mixin-0.13.4.tgz" "resolved" "https://registry.npmjs.org/react-timer-mixin/-/react-timer-mixin-0.13.4.tgz"
"version" "0.13.4" "version" "0.13.4"
@@ -8069,6 +8074,11 @@
"resolved" "https://registry.npmjs.org/slugify/-/slugify-1.4.7.tgz" "resolved" "https://registry.npmjs.org/slugify/-/slugify-1.4.7.tgz"
"version" "1.4.7" "version" "1.4.7"
"smart-mixin@^2.0.0":
"integrity" "sha1-o0oQVeMqdbMNK048oyPcmctT9Dc="
"resolved" "https://registry.npmjs.org/smart-mixin/-/smart-mixin-2.0.0.tgz"
"version" "2.0.0"
"snapdragon-node@^2.0.1": "snapdragon-node@^2.0.1":
"integrity" "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==" "integrity" "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw=="
"resolved" "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz" "resolved" "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz"