diff --git a/App.js b/App.js
index 3031c6f..7697b7c 100644
--- a/App.js
+++ b/App.js
@@ -1,6 +1,6 @@
-import 'expo-dev-client';
import { ApolloProvider } from "@apollo/client";
import "expo-asset";
+import 'expo-dev-client';
import "intl";
import "intl/locale-data/jsonp/en";
import { SafeAreaProvider } from "react-native-safe-area-context";
diff --git a/app/_layout.tsx b/app/_layout.tsx
index 620ea20..df04d73 100644
--- a/app/_layout.tsx
+++ b/app/_layout.tsx
@@ -1,29 +1,93 @@
+import { checkUserSession } from "@/redux/user/user.actions";
+import { selectBodyshop, selectCurrentUser } from "@/redux/user/user.selectors";
import { ApolloProvider } from "@apollo/client";
+import { Stack } from "expo-router";
import { Icon, Label, NativeTabs } from "expo-router/unstable-native-tabs";
+import { useEffect } from "react";
import { useTranslation } from "react-i18next";
-import { Provider } from "react-redux";
+import { ActivityIndicator, View } from "react-native";
+import { MD3LightTheme, Provider as PaperProvider } from "react-native-paper";
+import { connect, Provider } from "react-redux";
import { PersistGate } from "redux-persist/integration/react";
+import { createStructuredSelector } from "reselect";
import { client } from "../graphql/client";
import { persistor, store } from "../redux/store";
import "../translations/i18n";
-export default function TabLayout() {
+function AuthenticatedLayout() {
const { t } = useTranslation();
+ return (
+
+
+
+
+
+
+
+
+
+
+ );
+}
+function UnauthenticatedLayout() {
+ return (
+
+
+
+ );
+}
+
+function LoadingLayout() {
+ return (
+
+
+
+ );
+}
+
+const mapStateToProps = createStructuredSelector({
+ bodyshop: selectBodyshop,
+ currentUser: selectCurrentUser,
+});
+const mapDispatchToProps = (dispatch) => ({
+ checkUserSession: () => dispatch(checkUserSession()),
+});
+function AppContent({ currentUser, checkUserSession, bodyshop }) {
+ useEffect(() => {
+ checkUserSession();
+ }, []);
+
+ if (currentUser.authorized === null) {
+ return ;
+ }
+ if (currentUser.authorized) {
+ return ;
+ }
+ return ;
+}
+const ConnectedAppContent = connect(
+ mapStateToProps,
+ mapDispatchToProps
+)(AppContent);
+
+const theme = {
+ ...MD3LightTheme,
+ colors: {
+ ...MD3LightTheme.colors,
+ primary: "#1890ff",
+ accent: "tomato",
+ },
+};
+
+export default function AppLayout() {
return (
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/app/index.tsx b/app/index.tsx
index 127e318..e006d8e 100644
--- a/app/index.tsx
+++ b/app/index.tsx
@@ -1,5 +1,17 @@
+import { selectCurrentUser } from "@/redux/user/user.selectors";
import { Redirect } from "expo-router";
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
-export default function Index() {
- return ;
+const mapStateToProps = createStructuredSelector({
+ currentUser: selectCurrentUser,
+});
+
+function Index({ currentUser }) {
+ if (currentUser.authorized) {
+ return ;
+ }
+
+ return ;
}
+export default connect(mapStateToProps, null)(Index);
diff --git a/app/settings.tsx b/app/settings.tsx
index 2aa5299..da1362b 100644
--- a/app/settings.tsx
+++ b/app/settings.tsx
@@ -1,9 +1,10 @@
-import { StyleSheet, Text, View } from 'react-native';
-
+import SignOutButton from "@/components-old/sign-out-button/sign-out-button.component";
+import { StyleSheet, Text, View } from "react-native";
export default function Tab() {
return (
Tab [Home|Settings]
+
);
}
@@ -11,7 +12,7 @@ export default function Tab() {
const styles = StyleSheet.create({
container: {
flex: 1,
- justifyContent: 'center',
- alignItems: 'center',
+ justifyContent: "center",
+ alignItems: "center",
},
});
diff --git a/app/sign-in.tsx b/app/sign-in.tsx
new file mode 100644
index 0000000..e72bcf8
--- /dev/null
+++ b/app/sign-in.tsx
@@ -0,0 +1,4 @@
+import SignIn from "@/components/sign-in/sign-in";
+export default function SignInScreen() {
+ return ;
+}
diff --git a/assets/logo192.png b/assets/images/logo192.png
similarity index 100%
rename from assets/logo192.png
rename to assets/images/logo192.png
diff --git a/components/external-link.tsx b/components/external-link.tsx
deleted file mode 100644
index 883e515..0000000
--- a/components/external-link.tsx
+++ /dev/null
@@ -1,25 +0,0 @@
-import { Href, Link } from 'expo-router';
-import { openBrowserAsync, WebBrowserPresentationStyle } from 'expo-web-browser';
-import { type ComponentProps } from 'react';
-
-type Props = Omit, 'href'> & { href: Href & string };
-
-export function ExternalLink({ href, ...rest }: Props) {
- return (
- {
- if (process.env.EXPO_OS !== 'web') {
- // Prevent the default behavior of linking to the default browser on native.
- event.preventDefault();
- // Open the link in an in-app browser.
- await openBrowserAsync(href, {
- presentationStyle: WebBrowserPresentationStyle.AUTOMATIC,
- });
- }
- }}
- />
- );
-}
diff --git a/components/haptic-tab.tsx b/components/haptic-tab.tsx
deleted file mode 100644
index 7f3981c..0000000
--- a/components/haptic-tab.tsx
+++ /dev/null
@@ -1,18 +0,0 @@
-import { BottomTabBarButtonProps } from '@react-navigation/bottom-tabs';
-import { PlatformPressable } from '@react-navigation/elements';
-import * as Haptics from 'expo-haptics';
-
-export function HapticTab(props: BottomTabBarButtonProps) {
- return (
- {
- if (process.env.EXPO_OS === 'ios') {
- // Add a soft haptic feedback when pressing down on the tabs.
- Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
- }
- props.onPressIn?.(ev);
- }}
- />
- );
-}
diff --git a/components/hello-wave.tsx b/components/hello-wave.tsx
deleted file mode 100644
index 5def547..0000000
--- a/components/hello-wave.tsx
+++ /dev/null
@@ -1,19 +0,0 @@
-import Animated from 'react-native-reanimated';
-
-export function HelloWave() {
- return (
-
- 👋
-
- );
-}
diff --git a/components/parallax-scroll-view.tsx b/components/parallax-scroll-view.tsx
deleted file mode 100644
index 6f674a7..0000000
--- a/components/parallax-scroll-view.tsx
+++ /dev/null
@@ -1,79 +0,0 @@
-import type { PropsWithChildren, ReactElement } from 'react';
-import { StyleSheet } from 'react-native';
-import Animated, {
- interpolate,
- useAnimatedRef,
- useAnimatedStyle,
- useScrollOffset,
-} from 'react-native-reanimated';
-
-import { ThemedView } from '@/components/themed-view';
-import { useColorScheme } from '@/hooks/use-color-scheme';
-import { useThemeColor } from '@/hooks/use-theme-color';
-
-const HEADER_HEIGHT = 250;
-
-type Props = PropsWithChildren<{
- headerImage: ReactElement;
- headerBackgroundColor: { dark: string; light: string };
-}>;
-
-export default function ParallaxScrollView({
- children,
- headerImage,
- headerBackgroundColor,
-}: Props) {
- const backgroundColor = useThemeColor({}, 'background');
- const colorScheme = useColorScheme() ?? 'light';
- const scrollRef = useAnimatedRef();
- const scrollOffset = useScrollOffset(scrollRef);
- const headerAnimatedStyle = useAnimatedStyle(() => {
- return {
- transform: [
- {
- translateY: interpolate(
- scrollOffset.value,
- [-HEADER_HEIGHT, 0, HEADER_HEIGHT],
- [-HEADER_HEIGHT / 2, 0, HEADER_HEIGHT * 0.75]
- ),
- },
- {
- scale: interpolate(scrollOffset.value, [-HEADER_HEIGHT, 0, HEADER_HEIGHT], [2, 1, 1]),
- },
- ],
- };
- });
-
- return (
-
-
- {headerImage}
-
- {children}
-
- );
-}
-
-const styles = StyleSheet.create({
- container: {
- flex: 1,
- },
- header: {
- height: HEADER_HEIGHT,
- overflow: 'hidden',
- },
- content: {
- flex: 1,
- padding: 32,
- gap: 16,
- overflow: 'hidden',
- },
-});
diff --git a/components/sign-in/sign-in-error.jsx b/components/sign-in/sign-in-error.jsx
new file mode 100644
index 0000000..7f8f238
--- /dev/null
+++ b/components/sign-in/sign-in-error.jsx
@@ -0,0 +1,53 @@
+import { useEffect, useState } from "react";
+import { useTranslation } from "react-i18next";
+import { StyleSheet, View } from "react-native";
+import { Text } from "react-native-paper";
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
+import { selectSignInError } from "../../redux/user/user.selectors";
+
+const mapStateToProps = createStructuredSelector({
+ signInError: selectSignInError,
+});
+
+function SignInError({ signInError }) {
+ const [errorText, setErrorText] = useState("");
+ const { t } = useTranslation();
+
+ useEffect(() => {
+ let text;
+ if (signInError && signInError.code) {
+ switch (signInError.code) {
+ case "auth/user-not-found":
+ text = t("signin.errors.wronginfo");
+ break;
+ case "auth/invalid-email":
+ text = t("signin.errors.wronginfo");
+ break;
+ case "auth/wrong-password":
+ text = t("signin.errors.wronginfo");
+ break;
+ default:
+ text = signInError.code + " " + signInError.message;
+ break;
+ }
+ setErrorText(text);
+ }
+ }, [t, signInError, setErrorText]);
+ return (
+
+ {errorText ? {errorText} : null}
+
+ );
+}
+
+export default connect(mapStateToProps, null)(SignInError);
+
+const localStyles = StyleSheet.create({
+ alert: {
+ color: "red",
+ textAlign: "center",
+ margin: 15,
+ padding: 15,
+ },
+});
diff --git a/components/sign-in/sign-in.jsx b/components/sign-in/sign-in.jsx
new file mode 100644
index 0000000..5512b80
--- /dev/null
+++ b/components/sign-in/sign-in.jsx
@@ -0,0 +1,132 @@
+import { Formik } from "formik";
+import React from "react";
+import { useTranslation } from "react-i18next";
+import { Image, StyleSheet, View } from "react-native";
+import { Button, Text, TextInput } from "react-native-paper";
+import { connect } from "react-redux";
+import { createStructuredSelector } from "reselect";
+import { emailSignInStart } from "../../redux/user/user.actions";
+import SignInError from "./sign-in-error";
+
+import {
+ selectCurrentUser,
+ selectSigningIn,
+} from "../../redux/user/user.selectors";
+//import SignInErrorAlertComponent from "../sign-in-error-alert/sign-in-error-alert.component";
+import Constants from "expo-constants";
+
+const mapStateToProps = createStructuredSelector({
+ currentUser: selectCurrentUser,
+ signingIn: selectSigningIn,
+});
+
+const mapDispatchToProps = (dispatch) => ({
+ emailSignInStart: (email, password) =>
+ dispatch(emailSignInStart({ email, password })),
+});
+
+export function SignIn({ emailSignInStart, signingIn }) {
+ const { t } = useTranslation();
+
+ const formSubmit = (values) => {
+ const { email, password } = values;
+ emailSignInStart(email, password);
+ };
+
+ return (
+
+
+
+ {t("app.title")}
+
+
+
+ {({ handleChange, handleBlur, handleSubmit, values }) => (
+
+
+
+
+
+
+
+
+ )}
+
+
+
+ {t("settings.labels.version", {
+ number: Constants.expoConfig.version,
+ })}
+
+
+ );
+}
+const styles = StyleSheet.create({
+ container: {
+ flex: 1,
+ justifyContent: "center",
+ alignItems: "center",
+ display: "flex",
+ },
+ imageContainer: {
+ display: "flex",
+ marginTop: 80,
+ flexDirection: "row",
+ alignItems: "center",
+ justifyContent: "center",
+ gap: 10,
+ },
+ logo: {
+ maxWidth: "20%",
+ resizeMode: "contain",
+ },
+ formContainer: {
+ display: "flex",
+ width: "100%",
+ padding: 20,
+ gap: 10,
+ },
+ // content: {
+ // display: "flex",
+ // flex: 1,
+ // },
+ // logo: { width: 100, height: 100 },
+ inputContainer: {
+ marginBottom: 20,
+ display: "flex",
+ },
+ input: {},
+ footer: {
+ padding: 10,
+ alignSelf: "center",
+ },
+});
+
+export default connect(mapStateToProps, mapDispatchToProps)(SignIn);
diff --git a/components/themed-text.tsx b/components/themed-text.tsx
deleted file mode 100644
index d79d0a1..0000000
--- a/components/themed-text.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import { StyleSheet, Text, type TextProps } from 'react-native';
-
-import { useThemeColor } from '@/hooks/use-theme-color';
-
-export type ThemedTextProps = TextProps & {
- lightColor?: string;
- darkColor?: string;
- type?: 'default' | 'title' | 'defaultSemiBold' | 'subtitle' | 'link';
-};
-
-export function ThemedText({
- style,
- lightColor,
- darkColor,
- type = 'default',
- ...rest
-}: ThemedTextProps) {
- const color = useThemeColor({ light: lightColor, dark: darkColor }, 'text');
-
- return (
-
- );
-}
-
-const styles = StyleSheet.create({
- default: {
- fontSize: 16,
- lineHeight: 24,
- },
- defaultSemiBold: {
- fontSize: 16,
- lineHeight: 24,
- fontWeight: '600',
- },
- title: {
- fontSize: 32,
- fontWeight: 'bold',
- lineHeight: 32,
- },
- subtitle: {
- fontSize: 20,
- fontWeight: 'bold',
- },
- link: {
- lineHeight: 30,
- fontSize: 16,
- color: '#0a7ea4',
- },
-});
diff --git a/components/themed-view.tsx b/components/themed-view.tsx
deleted file mode 100644
index 6f181d8..0000000
--- a/components/themed-view.tsx
+++ /dev/null
@@ -1,14 +0,0 @@
-import { View, type ViewProps } from 'react-native';
-
-import { useThemeColor } from '@/hooks/use-theme-color';
-
-export type ThemedViewProps = ViewProps & {
- lightColor?: string;
- darkColor?: string;
-};
-
-export function ThemedView({ style, lightColor, darkColor, ...otherProps }: ThemedViewProps) {
- const backgroundColor = useThemeColor({ light: lightColor, dark: darkColor }, 'background');
-
- return ;
-}
diff --git a/components/ui/collapsible.tsx b/components/ui/collapsible.tsx
deleted file mode 100644
index 6345fde..0000000
--- a/components/ui/collapsible.tsx
+++ /dev/null
@@ -1,45 +0,0 @@
-import { PropsWithChildren, useState } from 'react';
-import { StyleSheet, TouchableOpacity } from 'react-native';
-
-import { ThemedText } from '@/components/themed-text';
-import { ThemedView } from '@/components/themed-view';
-import { IconSymbol } from '@/components/ui/icon-symbol';
-import { Colors } from '@/constants/theme';
-import { useColorScheme } from '@/hooks/use-color-scheme';
-
-export function Collapsible({ children, title }: PropsWithChildren & { title: string }) {
- const [isOpen, setIsOpen] = useState(false);
- const theme = useColorScheme() ?? 'light';
-
- return (
-
- setIsOpen((value) => !value)}
- activeOpacity={0.8}>
-
-
- {title}
-
- {isOpen && {children}}
-
- );
-}
-
-const styles = StyleSheet.create({
- heading: {
- flexDirection: 'row',
- alignItems: 'center',
- gap: 6,
- },
- content: {
- marginTop: 6,
- marginLeft: 24,
- },
-});
diff --git a/components/ui/icon-symbol.ios.tsx b/components/ui/icon-symbol.ios.tsx
deleted file mode 100644
index 9177f4d..0000000
--- a/components/ui/icon-symbol.ios.tsx
+++ /dev/null
@@ -1,32 +0,0 @@
-import { SymbolView, SymbolViewProps, SymbolWeight } from 'expo-symbols';
-import { StyleProp, ViewStyle } from 'react-native';
-
-export function IconSymbol({
- name,
- size = 24,
- color,
- style,
- weight = 'regular',
-}: {
- name: SymbolViewProps['name'];
- size?: number;
- color: string;
- style?: StyleProp;
- weight?: SymbolWeight;
-}) {
- return (
-
- );
-}
diff --git a/components/ui/icon-symbol.tsx b/components/ui/icon-symbol.tsx
deleted file mode 100644
index b7ece6b..0000000
--- a/components/ui/icon-symbol.tsx
+++ /dev/null
@@ -1,41 +0,0 @@
-// Fallback for using MaterialIcons on Android and web.
-
-import MaterialIcons from '@expo/vector-icons/MaterialIcons';
-import { SymbolWeight, SymbolViewProps } from 'expo-symbols';
-import { ComponentProps } from 'react';
-import { OpaqueColorValue, type StyleProp, type TextStyle } from 'react-native';
-
-type IconMapping = Record['name']>;
-type IconSymbolName = keyof typeof MAPPING;
-
-/**
- * Add your SF Symbols to Material Icons mappings here.
- * - see Material Icons in the [Icons Directory](https://icons.expo.fyi).
- * - see SF Symbols in the [SF Symbols](https://developer.apple.com/sf-symbols/) app.
- */
-const MAPPING = {
- 'house.fill': 'home',
- 'paperplane.fill': 'send',
- 'chevron.left.forwardslash.chevron.right': 'code',
- 'chevron.right': 'chevron-right',
-} as IconMapping;
-
-/**
- * An icon component that uses native SF Symbols on iOS, and Material Icons on Android and web.
- * This ensures a consistent look across platforms, and optimal resource usage.
- * Icon `name`s are based on SF Symbols and require manual mapping to Material Icons.
- */
-export function IconSymbol({
- name,
- size = 24,
- color,
- style,
-}: {
- name: IconSymbolName;
- size?: number;
- color: string | OpaqueColorValue;
- style?: StyleProp;
- weight?: SymbolWeight;
-}) {
- return ;
-}
diff --git a/package-lock.json b/package-lock.json
index f845eef..b98b6e2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,6 +11,7 @@
"@apollo/client": "^3.12.11",
"@expo/vector-icons": "^15.0.2",
"@react-native-async-storage/async-storage": "2.2.0",
+ "@react-native-vector-icons/material-design-icons": "^12.3.0",
"@react-navigation/bottom-tabs": "^7.4.0",
"@react-navigation/elements": "^2.6.3",
"@react-navigation/native": "^7.1.8",
@@ -53,6 +54,7 @@
"react-native": "0.81.4",
"react-native-gesture-handler": "~2.28.0",
"react-native-image-viewing": "^0.2.2",
+ "react-native-paper": "^5.14.5",
"react-native-reanimated": "~4.1.1",
"react-native-safe-area-context": "~5.6.0",
"react-native-screens": "~4.16.0",
@@ -1606,6 +1608,28 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@callstack/react-theme-provider": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/@callstack/react-theme-provider/-/react-theme-provider-3.0.9.tgz",
+ "integrity": "sha512-tTQ0uDSCL0ypeMa8T/E9wAZRGKWj8kXP7+6RYgPTfOPs9N07C9xM8P02GJ3feETap4Ux5S69D9nteq9mEj86NA==",
+ "license": "MIT",
+ "dependencies": {
+ "deepmerge": "^3.2.0",
+ "hoist-non-react-statics": "^3.3.0"
+ },
+ "peerDependencies": {
+ "react": ">=16.3.0"
+ }
+ },
+ "node_modules/@callstack/react-theme-provider/node_modules/deepmerge": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-3.3.0.tgz",
+ "integrity": "sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/@egjs/hammerjs": {
"version": "2.0.17",
"resolved": "https://registry.npmjs.org/@egjs/hammerjs/-/hammerjs-2.0.17.tgz",
@@ -4317,6 +4341,132 @@
"react-native": "^0.0.0-0 || >=0.65 <1.0"
}
},
+ "node_modules/@react-native-vector-icons/common": {
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-vector-icons/common/-/common-12.3.0.tgz",
+ "integrity": "sha512-5GMBcLBkA0MuciweYcrSyvi9fYGanfVnE2J+pwHx1QiaVgTaoCm4rylJgSS77MVI5qUiGh7aJpqq5afSz2U4bw==",
+ "license": "MIT",
+ "dependencies": {
+ "find-up": "^7.0.0",
+ "picocolors": "^1.1.1",
+ "plist": "^3.1.0"
+ },
+ "bin": {
+ "rnvi-update-plist": "lib/commonjs/scripts/updatePlist.js"
+ },
+ "engines": {
+ "node": ">= 18.0.0"
+ },
+ "peerDependencies": {
+ "@react-native-vector-icons/get-image": "^12.2.0",
+ "react": "*",
+ "react-native": "*"
+ },
+ "peerDependenciesMeta": {
+ "@react-native-vector-icons/get-image": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@react-native-vector-icons/common/node_modules/find-up": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/find-up/-/find-up-7.0.0.tgz",
+ "integrity": "sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==",
+ "license": "MIT",
+ "dependencies": {
+ "locate-path": "^7.2.0",
+ "path-exists": "^5.0.0",
+ "unicorn-magic": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@react-native-vector-icons/common/node_modules/locate-path": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz",
+ "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==",
+ "license": "MIT",
+ "dependencies": {
+ "p-locate": "^6.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@react-native-vector-icons/common/node_modules/p-limit": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz",
+ "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==",
+ "license": "MIT",
+ "dependencies": {
+ "yocto-queue": "^1.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@react-native-vector-icons/common/node_modules/p-locate": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz",
+ "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==",
+ "license": "MIT",
+ "dependencies": {
+ "p-limit": "^4.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@react-native-vector-icons/common/node_modules/path-exists": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz",
+ "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==",
+ "license": "MIT",
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ }
+ },
+ "node_modules/@react-native-vector-icons/common/node_modules/yocto-queue": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz",
+ "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@react-native-vector-icons/material-design-icons": {
+ "version": "12.3.0",
+ "resolved": "https://registry.npmjs.org/@react-native-vector-icons/material-design-icons/-/material-design-icons-12.3.0.tgz",
+ "integrity": "sha512-0fut9zjUJtGWwjGQ0lbirmPnjMkou9vkBY3d3ZsaHqXCBgV3fGeOWuRZ17eDpsGy/9BTRtBRI85RYdFGhdcB4Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@react-native-vector-icons/common": "^12.3.0"
+ },
+ "engines": {
+ "node": ">= 18.0.0"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
"node_modules/@react-native/assets-registry": {
"version": "0.81.4",
"resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.81.4.tgz",
@@ -4911,7 +5061,6 @@
"version": "19.1.17",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.17.tgz",
"integrity": "sha512-Qec1E3mhALmaspIrhWt9jkQMNdw6bReVu64mjvhbhq2NFPftLPVr+l1SZgmw/66WwBNpDh7ao5AT6gF5v41PFA==",
- "dev": true,
"license": "MIT",
"dependencies": {
"csstype": "^3.0.2"
@@ -6843,7 +6992,6 @@
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
- "dev": true,
"license": "MIT"
},
"node_modules/data-view-buffer": {
@@ -12678,6 +12826,62 @@
"react-native": "*"
}
},
+ "node_modules/react-native-pager-view": {
+ "version": "6.9.1",
+ "resolved": "https://registry.npmjs.org/react-native-pager-view/-/react-native-pager-view-6.9.1.tgz",
+ "integrity": "sha512-uUT0MMMbNtoSbxe9pRvdJJKEi9snjuJ3fXlZhG8F2vVMOBJVt/AFtqMPUHu9yMflmqOr08PewKzj9EPl/Yj+Gw==",
+ "license": "MIT",
+ "peer": true,
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*"
+ }
+ },
+ "node_modules/react-native-paper": {
+ "version": "5.14.5",
+ "resolved": "https://registry.npmjs.org/react-native-paper/-/react-native-paper-5.14.5.tgz",
+ "integrity": "sha512-eaIH5bUQjJ/mYm4AkI6caaiyc7BcHDwX6CqNDi6RIxfxfWxROsHpll1oBuwn/cFvknvA8uEAkqLk/vzVihI3AQ==",
+ "license": "MIT",
+ "workspaces": [
+ "example",
+ "docs"
+ ],
+ "dependencies": {
+ "@callstack/react-theme-provider": "^3.0.9",
+ "color": "^3.1.2",
+ "use-latest-callback": "^0.2.3"
+ },
+ "peerDependencies": {
+ "react": "*",
+ "react-native": "*",
+ "react-native-safe-area-context": "*"
+ }
+ },
+ "node_modules/react-native-paper/node_modules/color": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/color/-/color-3.2.1.tgz",
+ "integrity": "sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==",
+ "license": "MIT",
+ "dependencies": {
+ "color-convert": "^1.9.3",
+ "color-string": "^1.6.0"
+ }
+ },
+ "node_modules/react-native-paper/node_modules/color-convert": {
+ "version": "1.9.3",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+ "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "1.1.3"
+ }
+ },
+ "node_modules/react-native-paper/node_modules/color-name": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+ "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
+ "license": "MIT"
+ },
"node_modules/react-native-reanimated": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/react-native-reanimated/-/react-native-reanimated-4.1.2.tgz",
@@ -14671,7 +14875,7 @@
"version": "5.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
"integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
- "dev": true,
+ "devOptional": true,
"license": "Apache-2.0",
"bin": {
"tsc": "bin/tsc",
@@ -14779,6 +14983,18 @@
"node": ">=4"
}
},
+ "node_modules/unicorn-magic": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz",
+ "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/unique-string": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz",
diff --git a/package.json b/package.json
index 0da71c7..764c727 100644
--- a/package.json
+++ b/package.json
@@ -20,44 +20,36 @@
"lint": "expo lint"
},
"dependencies": {
+ "@apollo/client": "^3.12.11",
"@expo/vector-icons": "^15.0.2",
+ "@react-native-async-storage/async-storage": "2.2.0",
+ "@react-native-vector-icons/material-design-icons": "^12.3.0",
"@react-navigation/bottom-tabs": "^7.4.0",
"@react-navigation/elements": "^2.6.3",
"@react-navigation/native": "^7.1.8",
+ "@reduxjs/toolkit": "^2.9.0",
+ "axios": "^1.12.2",
+ "dinero.js": "^1.9.1",
"expo": "~54.0.12",
+ "expo-application": "~7.0.7",
"expo-constants": "~18.0.9",
+ "expo-dev-client": "~6.0.13",
+ "expo-file-system": "~19.0.16",
"expo-font": "~14.0.8",
"expo-haptics": "~15.0.7",
"expo-image": "~3.0.8",
+ "expo-image-picker": "~17.0.8",
"expo-linking": "~8.0.8",
+ "expo-localization": "~17.0.7",
+ "expo-media-library": "~18.2.0",
+ "expo-notifications": "~0.32.12",
"expo-router": "~6.0.10",
"expo-splash-screen": "~31.0.10",
"expo-status-bar": "~3.0.8",
"expo-symbols": "~1.0.7",
"expo-system-ui": "~6.0.7",
- "expo-web-browser": "~15.0.8",
- "react": "19.1.0",
- "react-dom": "19.1.0",
- "react-native": "0.81.4",
- "react-native-gesture-handler": "~2.28.0",
- "react-native-worklets": "0.5.1",
- "react-native-reanimated": "~4.1.1",
- "react-native-safe-area-context": "~5.6.0",
- "react-native-screens": "~4.16.0",
- "react-native-web": "~0.21.0",
- "expo-application": "~7.0.7",
- "@apollo/client": "^3.12.11",
- "@react-native-async-storage/async-storage": "2.2.0",
- "@reduxjs/toolkit": "^2.9.0",
- "dinero.js": "^1.9.1",
- "axios": "^1.12.2",
- "expo-dev-client": "~6.0.13",
- "expo-file-system": "~19.0.16",
- "expo-image-picker": "~17.0.8",
- "expo-localization": "~17.0.7",
- "expo-media-library": "~18.2.0",
- "expo-notifications": "~0.32.12",
"expo-updates": "~29.0.12",
+ "expo-web-browser": "~15.0.8",
"firebase": "^12.3.0",
"formik": "^2.4.6",
"graphql": "^16.11.0",
@@ -68,9 +60,19 @@
"mime": "^4.1.0",
"moment": "^2.30.1",
"normalize-url": "^8.1.0",
+ "react": "19.1.0",
+ "react-dom": "19.1.0",
"react-i18next": "^16.0.0",
+ "react-native": "0.81.4",
+ "react-native-gesture-handler": "~2.28.0",
"react-native-image-viewing": "^0.2.2",
+ "react-native-paper": "^5.14.5",
+ "react-native-reanimated": "~4.1.1",
+ "react-native-safe-area-context": "~5.6.0",
+ "react-native-screens": "~4.16.0",
"react-native-tab-view": "4.1.3",
+ "react-native-web": "~0.21.0",
+ "react-native-worklets": "0.5.1",
"react-redux": "^9.2.0",
"redux": "^5.0.1",
"redux-logger": "^3.0.6",
@@ -80,8 +82,8 @@
},
"devDependencies": {
"@types/react": "~19.1.0",
- "typescript": "~5.9.2",
"eslint": "^9.25.0",
- "eslint-config-expo": "~10.0.0"
+ "eslint-config-expo": "~10.0.0",
+ "typescript": "~5.9.2"
}
}
diff --git a/translations/en-US/common.json b/translations/en-US/common.json
index 153ab06..610fb74 100644
--- a/translations/en-US/common.json
+++ b/translations/en-US/common.json
@@ -1,310 +1,311 @@
{
- "translation": {
- "app": {
- "nomobileaccess": "Your shop does not currently have access to ImEX Mobile. ",
- "title": "ImEX Mobile"
- },
- "camera": {
- "titles": {
- "cameratab": "Camera"
- }
- },
- "general": {
- "actions": {
- "signout": "Sign Out"
- },
- "labels": {
- "na": "N/A"
- }
- },
- "jobdetail": {
- "labels": {
- "claiminformation": "Claim Information",
- "dates": "Dates",
- "documents": "Docs",
- "employeeassignments": "Employee Assignments",
- "job": "Job",
- "jobinfo": "Job Information",
- "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.",
- "notes": "Notes"
- },
- "lbr_types": {
- "LA1": "LA1",
- "LA2": "LA2",
- "LA3": "LA3",
- "LA4": "LA4",
- "LAA": "Aluminum",
- "LAB": "Body",
- "LAD": "Diagnostic",
- "LAE": "Electrical",
- "LAF": "Frame",
- "LAG": "Glass",
- "LAM": "Mechanical",
- "LAR": "Refinish",
- "LAS": "Structural",
- "LAU": "User Defined"
- },
- "part_types": {
- "CCC": "CC Cleaning",
- "CCD": "CC Damage Waiver",
- "CCDR": "CC Daily Rate",
- "CCF": "CC Refuel",
- "CCM": "CC Mileage",
- "PAA": "Aftermarket",
- "PAC": "Rechromed",
- "PAE": "Existing",
- "PAL": "LKQ",
- "PAM": "Remanufactured",
- "PAN": "New/OEM",
- "PAO": "Other",
- "PAP": "OEM Partial",
- "PAR": "Recored",
- "PAS": "Sublet",
- "PASL": "Sublet"
- }
- },
- "joblist": {
- "actions": {
- "refresh": "Refresh",
- "swipecamera": "Add Pictures/Video"
- },
- "labels": {
- "activejobs": "Jobs",
- "detail": "Job Detail",
- "nojobs": "There are no active jobs.",
- "search": "Search..."
- },
- "titles": {
- "jobtab": "Jobs"
- }
- },
- "mediabrowser": {
- "actions": {
- "refresh": "Refresh",
- "upload": "Upload"
- },
- "labels": {
- "converting": "Converting",
- "deleteafterupload": "Delete After Upload",
- "localserver": "Local Server URL: {{url}}",
- "nomedia": "Look's like there's no media on your device. Take some photos or videos and they will appear here.",
- "selectjob": "--- Select a job ---",
- "selectjobassetselector": "Please select a job to upload media. ",
- "storageexceeded": "Unable to uploaded selected files because there is not sufficient space available on this job.",
- "storageexceeded_title": "Unable to upload file(s)",
- "storageused": "Storage Used: {{used}} / {{total}} ({{percent}}%)",
- "temporarystorage": "* Temporary Storage *",
- "uploading": "Uploading"
- },
- "titles": {
- "mediabrowsertab": "Media Browser"
- }
- },
- "mediacache": {
- "actions": {
- "deleteall": "Delete All",
- "uploadall": "Upload All"
- },
- "titles": {
- "mediacachetab": "Media"
- }
- },
- "messaging": {
- "titles": {
- "messagingtab": "Messaging"
- }
- },
- "more": {
- "titles": {
- "moretab": "More"
- }
- },
- "objects": {
- "jobs": {
- "fields": {
- "actual_completion": "Actual Completion",
- "actual_delivery": "Actual Delivery",
- "actual_in": "Actual In",
- "adjustment_bottom_line": "Adjustments",
- "ca_gst_registrant": "GST Registrant",
- "category": "Category",
- "ccc": "CC Cleaning",
- "ccd": "CC Damage Waiver",
- "ccdr": "CC Daily Rate",
- "ccf": "CC Refuel",
- "ccm": "CC Mileage",
- "cieca_id": "CIECA ID",
- "claim_total": "Claim Total",
- "class": "Class",
- "clm_no": "Claim #",
- "clm_total": "Claim Total",
- "csr": "Customer Service Rep.",
- "customerowing": "Customer Owing",
- "date_closed": "Closed",
- "date_estimated": "Date Estimated",
- "date_exported": "Exported",
- "date_invoiced": "Invoiced",
- "date_open": "Open",
- "date_scheduled": "Scheduled",
- "ded_amt": "Deductible",
- "ded_status": "Deductible Status",
- "depreciation_taxes": "Depreciation/Taxes",
- "employee_body": "Body",
- "employee_csr": "CSR",
- "employee_prep": "Prep",
- "employee_refinish": "Refinish",
- "est_addr1": "Appraiser Address",
- "est_co_nm": "Appraiser",
- "est_ct_fn": "Appraiser First Name",
- "est_ct_ln": "Appraiser Last Name",
- "est_ea": "Appraiser Email",
- "est_number": "Estimate #",
- "est_ph1": "Appraiser Phone #",
- "federal_tax_payable": "Federal Tax Payable",
- "federal_tax_rate": "Federal Tax Rate",
- "ins_addr1": "Insurance Co. Address",
- "ins_city": "Insurance City",
- "ins_co_id": "Insurance Co. ID",
- "ins_co_nm": "Insurance Company Name",
- "ins_ct_fn": "File Handler First Name",
- "ins_ct_ln": "File Handler Last Name",
- "ins_ea": "File Handler Email",
- "ins_ph1": "File Handler Phone #",
- "intake": {
- "label": "Label",
- "name": "Name",
- "required": "Required?",
- "type": "Type"
- },
- "kmin": "Mileage In",
- "kmout": "Mileage Out",
- "la1": "LA1",
- "la2": "LA2",
- "la3": "LA3",
- "la4": "LA4",
- "laa": "Aluminum ",
- "lab": "Body",
- "labor_rate_desc": "Labor Rate Name",
- "lad": "Diagnostic",
- "lae": "Electrical",
- "laf": "Frame",
- "lag": "Glass",
- "lam": "Mechanical",
- "lar": "Refinish",
- "las": "Structural",
- "lau": "LAU",
- "local_tax_rate": "Local Tax Rate",
- "loss_date": "Loss Date",
- "loss_desc": "Loss Description",
- "ma2s": "2 Stage Paint",
- "ma3s": "3 Stage Pain",
- "mabl": "MABL?",
- "macs": "MACS?",
- "mahw": "Hazardous Waste",
- "mapa": "Paint Materials",
- "mash": "Shop Materials",
- "matd": "Tire Disposal",
- "other_amount_payable": "Other Amount Payable",
- "owner": "Owner",
- "owner_owing": "Cust. Owes",
- "ownr_ea": "Email",
- "ownr_ph1": "Phone 1",
- "paa": "Aftermarket",
- "pae": "Existing",
- "pal": "LKQ",
- "pam": "Remanufactured",
- "pan": "OEM/New",
- "pao": "Other",
- "pap": "EOM Partial",
- "par": "Re-cored",
- "pas": "Sublet",
- "pay_date": "Pay Date",
- "phoneshort": "PH",
- "policy_no": "Policy #",
- "ponumber": "PO Number",
- "rate_la1": "LA1",
- "rate_la2": "LA2",
- "rate_la3": "LA3",
- "rate_la4": "LA4",
- "rate_laa": "Aluminum",
- "rate_lab": "Body",
- "rate_lad": "Diagnostic",
- "rate_lae": "Electrical",
- "rate_laf": "Frame",
- "rate_lag": "Glass",
- "rate_lam": "Mechanical",
- "rate_lar": "Refinish",
- "rate_las": "Sublet",
- "rate_lau": "Aluminum",
- "rate_ma2s": "2 Stage Paint",
- "rate_ma3s": "3 Stage Paint",
- "rate_mabl": "MABL??",
- "rate_macs": "MACS??",
- "rate_mahw": "Hazardous Waste",
- "rate_mapa": "Paint Materials",
- "rate_mash": "Shop Material",
- "rate_matd": "Tire Disposal",
- "referralsource": "Referral Source",
- "regie_number": "Registration #",
- "repairtotal": "Repair Total",
- "ro_number": "RO #",
- "scheduled_completion": "Scheduled Completion",
- "scheduled_delivery": "Scheduled Delivery",
- "scheduled_in": "Scheduled In",
- "selling_dealer": "Selling Dealer",
- "selling_dealer_contact": "Selling Dealer Contact",
- "servicecar": "Service Car",
- "servicing_dealer": "Servicing Dealer",
- "servicing_dealer_contact": "Servicing Dealer Contact",
- "specialcoveragepolicy": "Special Coverage Policy",
- "state_tax_rate": "State Tax Rate",
- "status": "Job Status",
- "storage_payable": "Storage/PVRT",
- "tax_registration_number": "Tax Registration Number",
- "towing_payable": "Towing Payable",
- "unitnumber": "Unit #",
- "updated_at": "Updated At",
- "uploaded_by": "Uploaded By",
- "vehicle": "Vehicle"
- },
- "labels": {
- "inproduction": "In Production"
- }
- }
- },
- "production": {
- "titles": {
- "production": "Production"
- }
- },
- "settings": {
- "labels": {
- "version": "Version {{number}}"
- },
- "titles": {
- "settings": "Settings"
- }
- },
- "signin": {
- "actions": {
- "signin": "Sign In"
- },
- "errors": {
- "emailformat": "The email you have entered is not formatted correctly. ",
- "usernotfound": "No user found.",
- "wrongpassword": "The password you entered is not correct."
- },
- "fields": {
- "email": "Email",
- "password": "Password"
- }
- }
- }
+ "translation": {
+ "app": {
+ "nomobileaccess": "Your shop does not currently have access to ImEX Mobile. ",
+ "title": "ImEX Mobile"
+ },
+ "camera": {
+ "titles": {
+ "cameratab": "Camera"
+ }
+ },
+ "general": {
+ "actions": {
+ "signout": "Sign Out"
+ },
+ "labels": {
+ "na": "N/A"
+ }
+ },
+ "jobdetail": {
+ "labels": {
+ "claiminformation": "Claim Information",
+ "dates": "Dates",
+ "documents": "Docs",
+ "employeeassignments": "Employee Assignments",
+ "job": "Job",
+ "jobinfo": "Job Information",
+ "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.",
+ "notes": "Notes"
+ },
+ "lbr_types": {
+ "LA1": "LA1",
+ "LA2": "LA2",
+ "LA3": "LA3",
+ "LA4": "LA4",
+ "LAA": "Aluminum",
+ "LAB": "Body",
+ "LAD": "Diagnostic",
+ "LAE": "Electrical",
+ "LAF": "Frame",
+ "LAG": "Glass",
+ "LAM": "Mechanical",
+ "LAR": "Refinish",
+ "LAS": "Structural",
+ "LAU": "User Defined"
+ },
+ "part_types": {
+ "CCC": "CC Cleaning",
+ "CCD": "CC Damage Waiver",
+ "CCDR": "CC Daily Rate",
+ "CCF": "CC Refuel",
+ "CCM": "CC Mileage",
+ "PAA": "Aftermarket",
+ "PAC": "Rechromed",
+ "PAE": "Existing",
+ "PAL": "LKQ",
+ "PAM": "Remanufactured",
+ "PAN": "New/OEM",
+ "PAO": "Other",
+ "PAP": "OEM Partial",
+ "PAR": "Recored",
+ "PAS": "Sublet",
+ "PASL": "Sublet"
+ }
+ },
+ "joblist": {
+ "actions": {
+ "refresh": "Refresh",
+ "swipecamera": "Add Pictures/Video"
+ },
+ "labels": {
+ "activejobs": "Jobs",
+ "detail": "Job Detail",
+ "nojobs": "There are no active jobs.",
+ "search": "Search..."
+ },
+ "titles": {
+ "jobtab": "Jobs"
+ }
+ },
+ "mediabrowser": {
+ "actions": {
+ "refresh": "Refresh",
+ "upload": "Upload"
+ },
+ "labels": {
+ "converting": "Converting",
+ "deleteafterupload": "Delete After Upload",
+ "localserver": "Local Server URL: {{url}}",
+ "nomedia": "Look's like there's no media on your device. Take some photos or videos and they will appear here.",
+ "selectjob": "--- Select a job ---",
+ "selectjobassetselector": "Please select a job to upload media. ",
+ "storageexceeded": "Unable to uploaded selected files because there is not sufficient space available on this job.",
+ "storageexceeded_title": "Unable to upload file(s)",
+ "storageused": "Storage Used: {{used}} / {{total}} ({{percent}}%)",
+ "temporarystorage": "* Temporary Storage *",
+ "uploading": "Uploading"
+ },
+ "titles": {
+ "mediabrowsertab": "Media Browser"
+ }
+ },
+ "mediacache": {
+ "actions": {
+ "deleteall": "Delete All",
+ "uploadall": "Upload All"
+ },
+ "titles": {
+ "mediacachetab": "Media"
+ }
+ },
+ "messaging": {
+ "titles": {
+ "messagingtab": "Messaging"
+ }
+ },
+ "more": {
+ "titles": {
+ "moretab": "More"
+ }
+ },
+ "objects": {
+ "jobs": {
+ "fields": {
+ "actual_completion": "Actual Completion",
+ "actual_delivery": "Actual Delivery",
+ "actual_in": "Actual In",
+ "adjustment_bottom_line": "Adjustments",
+ "ca_gst_registrant": "GST Registrant",
+ "category": "Category",
+ "ccc": "CC Cleaning",
+ "ccd": "CC Damage Waiver",
+ "ccdr": "CC Daily Rate",
+ "ccf": "CC Refuel",
+ "ccm": "CC Mileage",
+ "cieca_id": "CIECA ID",
+ "claim_total": "Claim Total",
+ "class": "Class",
+ "clm_no": "Claim #",
+ "clm_total": "Claim Total",
+ "csr": "Customer Service Rep.",
+ "customerowing": "Customer Owing",
+ "date_closed": "Closed",
+ "date_estimated": "Date Estimated",
+ "date_exported": "Exported",
+ "date_invoiced": "Invoiced",
+ "date_open": "Open",
+ "date_scheduled": "Scheduled",
+ "ded_amt": "Deductible",
+ "ded_status": "Deductible Status",
+ "depreciation_taxes": "Depreciation/Taxes",
+ "employee_body": "Body",
+ "employee_csr": "CSR",
+ "employee_prep": "Prep",
+ "employee_refinish": "Refinish",
+ "est_addr1": "Appraiser Address",
+ "est_co_nm": "Appraiser",
+ "est_ct_fn": "Appraiser First Name",
+ "est_ct_ln": "Appraiser Last Name",
+ "est_ea": "Appraiser Email",
+ "est_number": "Estimate #",
+ "est_ph1": "Appraiser Phone #",
+ "federal_tax_payable": "Federal Tax Payable",
+ "federal_tax_rate": "Federal Tax Rate",
+ "ins_addr1": "Insurance Co. Address",
+ "ins_city": "Insurance City",
+ "ins_co_id": "Insurance Co. ID",
+ "ins_co_nm": "Insurance Company Name",
+ "ins_ct_fn": "File Handler First Name",
+ "ins_ct_ln": "File Handler Last Name",
+ "ins_ea": "File Handler Email",
+ "ins_ph1": "File Handler Phone #",
+ "intake": {
+ "label": "Label",
+ "name": "Name",
+ "required": "Required?",
+ "type": "Type"
+ },
+ "kmin": "Mileage In",
+ "kmout": "Mileage Out",
+ "la1": "LA1",
+ "la2": "LA2",
+ "la3": "LA3",
+ "la4": "LA4",
+ "laa": "Aluminum ",
+ "lab": "Body",
+ "labor_rate_desc": "Labor Rate Name",
+ "lad": "Diagnostic",
+ "lae": "Electrical",
+ "laf": "Frame",
+ "lag": "Glass",
+ "lam": "Mechanical",
+ "lar": "Refinish",
+ "las": "Structural",
+ "lau": "LAU",
+ "local_tax_rate": "Local Tax Rate",
+ "loss_date": "Loss Date",
+ "loss_desc": "Loss Description",
+ "ma2s": "2 Stage Paint",
+ "ma3s": "3 Stage Pain",
+ "mabl": "MABL?",
+ "macs": "MACS?",
+ "mahw": "Hazardous Waste",
+ "mapa": "Paint Materials",
+ "mash": "Shop Materials",
+ "matd": "Tire Disposal",
+ "other_amount_payable": "Other Amount Payable",
+ "owner": "Owner",
+ "owner_owing": "Cust. Owes",
+ "ownr_ea": "Email",
+ "ownr_ph1": "Phone 1",
+ "paa": "Aftermarket",
+ "pae": "Existing",
+ "pal": "LKQ",
+ "pam": "Remanufactured",
+ "pan": "OEM/New",
+ "pao": "Other",
+ "pap": "EOM Partial",
+ "par": "Re-cored",
+ "pas": "Sublet",
+ "pay_date": "Pay Date",
+ "phoneshort": "PH",
+ "policy_no": "Policy #",
+ "ponumber": "PO Number",
+ "rate_la1": "LA1",
+ "rate_la2": "LA2",
+ "rate_la3": "LA3",
+ "rate_la4": "LA4",
+ "rate_laa": "Aluminum",
+ "rate_lab": "Body",
+ "rate_lad": "Diagnostic",
+ "rate_lae": "Electrical",
+ "rate_laf": "Frame",
+ "rate_lag": "Glass",
+ "rate_lam": "Mechanical",
+ "rate_lar": "Refinish",
+ "rate_las": "Sublet",
+ "rate_lau": "Aluminum",
+ "rate_ma2s": "2 Stage Paint",
+ "rate_ma3s": "3 Stage Paint",
+ "rate_mabl": "MABL??",
+ "rate_macs": "MACS??",
+ "rate_mahw": "Hazardous Waste",
+ "rate_mapa": "Paint Materials",
+ "rate_mash": "Shop Material",
+ "rate_matd": "Tire Disposal",
+ "referralsource": "Referral Source",
+ "regie_number": "Registration #",
+ "repairtotal": "Repair Total",
+ "ro_number": "RO #",
+ "scheduled_completion": "Scheduled Completion",
+ "scheduled_delivery": "Scheduled Delivery",
+ "scheduled_in": "Scheduled In",
+ "selling_dealer": "Selling Dealer",
+ "selling_dealer_contact": "Selling Dealer Contact",
+ "servicecar": "Service Car",
+ "servicing_dealer": "Servicing Dealer",
+ "servicing_dealer_contact": "Servicing Dealer Contact",
+ "specialcoveragepolicy": "Special Coverage Policy",
+ "state_tax_rate": "State Tax Rate",
+ "status": "Job Status",
+ "storage_payable": "Storage/PVRT",
+ "tax_registration_number": "Tax Registration Number",
+ "towing_payable": "Towing Payable",
+ "unitnumber": "Unit #",
+ "updated_at": "Updated At",
+ "uploaded_by": "Uploaded By",
+ "vehicle": "Vehicle"
+ },
+ "labels": {
+ "inproduction": "In Production"
+ }
+ }
+ },
+ "production": {
+ "titles": {
+ "production": "Production"
+ }
+ },
+ "settings": {
+ "labels": {
+ "version": "Version {{number}}"
+ },
+ "titles": {
+ "settings": "Settings"
+ }
+ },
+ "signin": {
+ "actions": {
+ "signin": "Sign In"
+ },
+ "errors": {
+ "emailformat": "The email you have entered is not formatted correctly. ",
+ "usernotfound": "No user found.",
+ "wronginfo": "The email or password you entered is not correct.",
+ "wrongpassword": "The password you entered is not correct."
+ },
+ "fields": {
+ "email": "Email",
+ "password": "Password"
+ }
+ }
+ }
}