diff --git a/bodyshop_translations.babel b/bodyshop_translations.babel index fbcd25a81..f63a4e31b 100644 --- a/bodyshop_translations.babel +++ b/bodyshop_translations.babel @@ -301,6 +301,27 @@ + + preview + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + reschedule false @@ -24108,6 +24129,612 @@ + + landing + + + bigfeature + + + subtitle + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + title + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + footer + + + company + + + about + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + contact + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + disclaimers + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + name + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + privacypolicy + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + io + + + help + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + name + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + status + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + slogan + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + hero + + + button + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + title + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + labels + + + features + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + managemyshop + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + pricing + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + pricing + + + basic + + + name + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + sub + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + essentials + + + name + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + sub + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + pricingtitle + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + pro + + + name + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + sub + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + title + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + unlimited + + + name + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + sub + false + + + + + + en-US + false + + + es-MX + false + + + fr-CA + false + + + + + + + + + menus diff --git a/client/package.json b/client/package.json index eeafdb4e5..f3843a26b 100644 --- a/client/package.json +++ b/client/package.json @@ -19,6 +19,7 @@ "craco-less": "^1.17.1", "dinero.js": "^1.8.1", "dotenv": "^9.0.2", + "enquire-js": "^0.2.1", "env-cmd": "^10.1.0", "exifr": "^7.0.0", "firebase": "^8.6.0", @@ -35,6 +36,8 @@ "preval.macro": "^5.0.0", "prop-types": "^15.7.2", "query-string": "^7.0.0", + "rc-queue-anim": "^1.8.5", + "rc-scroll-anim": "^2.7.6", "react": "^17.0.1", "react-big-calendar": "^0.33.2", "react-color": "^2.19.3", @@ -49,6 +52,7 @@ "react-resizable": "^3.0.1", "react-router-dom": "^5.2.0", "react-scripts": "^4.0.3", + "react-sublime-video": "^0.2.5", "react-virtualized": "^9.22.3", "recharts": "^2.0.7", "redux": "^4.1.0", diff --git a/client/src/App/App.container.jsx b/client/src/App/App.container.jsx index 0e73f8a07..e960e2143 100644 --- a/client/src/App/App.container.jsx +++ b/client/src/App/App.container.jsx @@ -6,7 +6,6 @@ import moment from "moment"; import React from "react"; import { useTranslation } from "react-i18next"; import GlobalLoadingBar from "../components/global-loading-bar/global-loading-bar.component"; -import JiraSupportComponent from "../components/jira-support-widget/jira-support-widget.component"; import client from "../utils/GraphQLClient"; import App from "./App"; moment.locale("en-US"); @@ -16,21 +15,6 @@ if (process.env.NODE_ENV === "production") LogRocket.init("gvfvfw/bodyshopapp"); export default function AppContainer() { const { t } = useTranslation(); - // useEffect(() => { - // // Include the Crisp code here, without the tags - // window.$crisp = []; - // window.CRISP_WEBSITE_ID = "36724f62-2eb0-4b29-9cdd-9905fb99913e"; - // var d = document; - // var s = d.createElement("script"); - // s.src = "https://client.crisp.chat/l.js"; - // s.async = 1; - // d.getElementsByTagName("head")[0].appendChild(s); - - // return () => { - // d.getElementsByTagName("head")[0].removeChild(s); - // }; - // }, []); - return ( - ); diff --git a/client/src/App/App.jsx b/client/src/App/App.jsx index fbaedfd0a..cab3be913 100644 --- a/client/src/App/App.jsx +++ b/client/src/App/App.jsx @@ -8,7 +8,7 @@ import DocumentEditorContainer from "../components/document-editor/document-edit import ErrorBoundary from "../components/error-boundary/error-boundary.component"; //Component Imports import LoadingSpinner from "../components/loading-spinner/loading-spinner.component"; -import AboutPage from "../pages/about/about.page"; +import DisclaimerPage from "../pages/disclaimer/disclaimer.page"; import TechPageContainer from "../pages/tech/tech.page.container"; import { setOnline } from "../redux/application/application.actions"; import { selectOnline } from "../redux/application/application.selectors"; @@ -17,7 +17,7 @@ import { selectCurrentUser } from "../redux/user/user.selectors"; import PrivateRoute from "../utils/private-route"; import "./App.styles.scss"; -const LandingPage = lazy(() => import("../pages/landing/landing.page")); +import LandingPage from "../pages/landing/landing.page"; const ResetPassword = lazy(() => import("../pages/reset-password/reset-password.component") ); @@ -100,7 +100,7 @@ export function App({ checkUserSession, currentUser, online, setOnline }) { - + \ No newline at end of file diff --git a/client/src/components/breadcrumbs/breadcrumbs.component.jsx b/client/src/components/breadcrumbs/breadcrumbs.component.jsx index 9ad6c7fdb..ed3331da1 100644 --- a/client/src/components/breadcrumbs/breadcrumbs.component.jsx +++ b/client/src/components/breadcrumbs/breadcrumbs.component.jsx @@ -1,5 +1,5 @@ import { HomeFilled } from "@ant-design/icons"; -import { Breadcrumb } from "antd"; +import { Breadcrumb, Row, Col } from "antd"; import React from "react"; import { connect } from "react-redux"; import { Link } from "react-router-dom"; @@ -14,27 +14,29 @@ const mapStateToProps = createStructuredSelector({ export function BreadCrumbs({ breadcrumbs }) { return ( -
- - - - - - - {breadcrumbs.map((item) => - item.link ? ( - - {item.label} - - ) : ( - {item.label} - ) - )} - -
+ + + + + + + + + {breadcrumbs.map((item) => + item.link ? ( + + {item.label} + + ) : ( + {item.label} + ) + )} + + + -
-
+ + ); } export default connect(mapStateToProps, null)(BreadCrumbs); diff --git a/client/src/components/global-search/global-search.component.jsx b/client/src/components/global-search/global-search.component.jsx index cd146ffe3..0e5ddf8c8 100644 --- a/client/src/components/global-search/global-search.component.jsx +++ b/client/src/components/global-search/global-search.component.jsx @@ -37,7 +37,7 @@ export default function GlobalSearch() { value: job.ro_number, label: ( - }> + }> {job.ro_number || t("general.labels.na")} {`${job.ownr_fn || ""} ${job.ownr_ln || ""} ${ job.ownr_co_nm || "" @@ -62,7 +62,7 @@ export default function GlobalSearch() { }`, label: ( - }> + }> {`${owner.ownr_fn || ""} ${owner.ownr_ln || ""} ${ owner.ownr_co_nm || "" }`} @@ -85,7 +85,7 @@ export default function GlobalSearch() { } ${vehicle.v_model_desc || ""}`, label: ( - }> + }> {`${vehicle.v_model_yr || ""} ${ vehicle.v_make_desc || "" @@ -107,7 +107,7 @@ export default function GlobalSearch() { value: `${payment.job.ro_number} ${payment.payer} ${payment.amount}`, label: ( - }> + }> {payment.job.ro_number} {payment.job.memo} {payment.job.amount} @@ -126,7 +126,7 @@ export default function GlobalSearch() { value: `${bill.invoice_number} - ${bill.vendor.name}`, label: ( - }> + }> {bill.invoice_number} {bill.vendor.name} {bill.date} @@ -146,7 +146,7 @@ export default function GlobalSearch() { }`, label: ( - }> + }> {`${pb.firstname || ""} ${pb.lastname || ""} ${ pb.company || "" }`} @@ -165,8 +165,6 @@ export default function GlobalSearch() { return ( ; -} - -// const useScript = () => { -// useEffect(() => { -// const script = document.createElement("script"); -// script.src = "https://jsd-widget.atlassian.com/assets/embed.js"; -// script.setAttribute("data-jsd-embedded", true); -// script.setAttribute("data-key", "d69bb65c-1dd3-483f-b109-66a970d03f44"); -// script.setAttribute("data-base-url", "https://jsd-widget.atlassian.com"); -// //script.async = true; -// script.onload = () => { -// var DOMContentLoaded_event = document.createEvent("Event"); -// DOMContentLoaded_event.initEvent("DOMContentLoaded", true, true); -// window.document.dispatchEvent(DOMContentLoaded_event); -// }; -// document.head.appendChild(script); - -// return () => { -// document.head.removeChild(script); -// }; -// }, []); -// }; diff --git a/client/src/components/job-at-change/schedule-event.component.jsx b/client/src/components/job-at-change/schedule-event.component.jsx index 41bdb24d6..6e1b0b11d 100644 --- a/client/src/components/job-at-change/schedule-event.component.jsx +++ b/client/src/components/job-at-change/schedule-event.component.jsx @@ -2,7 +2,7 @@ import { Button, Popover, Space } from "antd"; import React, { useState } from "react"; import { useTranslation } from "react-i18next"; import { connect } from "react-redux"; -import { Link } from "react-router-dom"; +import { Link, useHistory, useLocation } from "react-router-dom"; import { setModalContext } from "../../redux/modals/modals.actions"; import CurrencyFormatter from "../../utils/CurrencyFormatter"; import PhoneFormatter from "../../utils/PhoneFormatter"; @@ -11,6 +11,8 @@ import { TemplateList } from "../../utils/TemplateConstants"; import DataLabel from "../data-label/data-label.component"; import ScheduleAtChange from "./job-at-change.component"; import ScheduleEventColor from "./schedule-event.color.component"; +import queryString from "query-string"; + const mapDispatchToProps = (dispatch) => ({ setScheduleContext: (context) => dispatch(setModalContext({ context: context, modal: "schedule" })), @@ -24,6 +26,8 @@ export function ScheduleEventComponent({ }) { const { t } = useTranslation(); const [visible, setVisible] = useState(false); + const history = useHistory(); + const searchParams = queryString.parse(useLocation().search); const blockContent = (
@@ -88,6 +92,20 @@ export function ScheduleEventComponent({ ) : null} + {event.job ? ( + + ) : null} - - - ); - notification.open({ - icon: , - message: i18n.t("general.messages.newversiontitle"), - description: i18n.t("general.messages.newversionmessage"), - duration: 0, - btn, - key: "updateavailable", - }); -}; +// const btn = ( +// +// +// +// +// ); +// notification.open({ +// icon: , +// message: i18n.t("general.messages.newversiontitle"), +// description: i18n.t("general.messages.newversionmessage"), +// duration: 0, +// btn, +// key: "updateavailable", +// }); +// }; -serviceWorkerRegistration.register({ onUpdate: onServiceWorkerUpdate }); +// serviceWorkerRegistration.register({ onUpdate: onServiceWorkerUpdate }); reportWebVitals(); diff --git a/client/src/landing/Banner0.jsx b/client/src/landing/Banner0.jsx new file mode 100644 index 000000000..9b8ef68c8 --- /dev/null +++ b/client/src/landing/Banner0.jsx @@ -0,0 +1,53 @@ +import React from 'react'; +import { Button } from 'antd'; +import { DownOutlined } from '@ant-design/icons'; +import QueueAnim from 'rc-queue-anim'; +import TweenOne from 'rc-tween-one'; +import { isImg } from './utils'; + +class Banner extends React.PureComponent { + render() { + const { ...currentProps } = this.props; + const { dataSource } = currentProps; + delete currentProps.dataSource; + delete currentProps.isMobile; + return ( +
+ +
+ {typeof dataSource.title.children === 'string' && + dataSource.title.children.match(isImg) ? ( + img + ) : ( + dataSource.title.children + )} +
+
+ {dataSource.content.children} +
+ +
+ + + +
+ ); + } +} +export default Banner; diff --git a/client/src/landing/Content0.jsx b/client/src/landing/Content0.jsx new file mode 100644 index 000000000..ab9e51526 --- /dev/null +++ b/client/src/landing/Content0.jsx @@ -0,0 +1,49 @@ +import React from 'react'; +import QueueAnim from 'rc-queue-anim'; +import { Row, Col } from 'antd'; +import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; +import { getChildrenToRender } from './utils'; + +class Content extends React.PureComponent { + render() { + const { dataSource, isMobile, ...props } = this.props; + const { + wrapper, + titleWrapper, + page, + OverPack: overPackData, + childWrapper, + } = dataSource; + return ( +
+
+
+ {titleWrapper.children.map(getChildrenToRender)} +
+ + + {childWrapper.children.map((block, i) => { + const { children: item, ...blockProps } = block; + return ( + +
+ {item.children.map(getChildrenToRender)} +
+ + ); + })} +
+
+
+
+ ); + } +} + +export default Content; diff --git a/client/src/landing/Content1.jsx b/client/src/landing/Content1.jsx new file mode 100644 index 000000000..66e6425ee --- /dev/null +++ b/client/src/landing/Content1.jsx @@ -0,0 +1,70 @@ +import React from 'react'; +import QueueAnim from 'rc-queue-anim'; +import TweenOne from 'rc-tween-one'; +import { Row, Col } from 'antd'; +import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; + +function Content1(props) { + const { ...tagProps } = props; + const { dataSource, isMobile } = tagProps; + delete tagProps.dataSource; + delete tagProps.isMobile; + const animType = { + queue: isMobile ? 'bottom' : 'right', + one: isMobile + ? { + scaleY: '+=0.3', + opacity: 0, + type: 'from', + ease: 'easeOutQuad', + } + : { + x: '-=30', + opacity: 0, + type: 'from', + ease: 'easeOutQuad', + }, + }; + return ( +
+ + + + img + + + +

+ {dataSource.title.children} +

+
+ {dataSource.content.children} +
+
+
+
+ ); +} + +export default Content1; diff --git a/client/src/landing/Content12.jsx b/client/src/landing/Content12.jsx new file mode 100644 index 000000000..b828b4c48 --- /dev/null +++ b/client/src/landing/Content12.jsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { Row, Col } from 'antd'; +import { TweenOneGroup } from 'rc-tween-one'; +import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; +import { getChildrenToRender } from './utils'; + +class Content12 extends React.PureComponent { + getChildrenToRender = (data) => + data.map((item) => { + return ( + +
+ + img + +
+ + ); + }); + + render() { + const { ...props } = this.props; + const { dataSource } = props; + delete props.dataSource; + delete props.isMobile; + const childrenToRender = this.getChildrenToRender( + dataSource.block.children + ); + return ( +
+
+
+ {dataSource.titleWrapper.children.map(getChildrenToRender)} +
+ + + {childrenToRender} + + +
+
+ ); + } +} + +export default Content12; diff --git a/client/src/landing/Content3.jsx b/client/src/landing/Content3.jsx new file mode 100644 index 000000000..49fe071ce --- /dev/null +++ b/client/src/landing/Content3.jsx @@ -0,0 +1,94 @@ +import React from 'react'; +import QueueAnim from 'rc-queue-anim'; +import TweenOne from 'rc-tween-one'; +import { Row, Col } from 'antd'; +import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; +import { getChildrenToRender } from './utils'; + +class Content3 extends React.PureComponent { + getDelay = (e, b) => (e % b) * 100 + Math.floor(e / b) * 100 + b * 100; + + render() { + const { ...props } = this.props; + const { dataSource, isMobile } = props; + delete props.dataSource; + delete props.isMobile; + let clearFloatNum = 0; + const children = dataSource.block.children.map((item, i) => { + const childObj = item.children; + const delay = isMobile ? i * 50 : this.getDelay(i, 24 / item.md); + const liAnim = { + opacity: 0, + type: 'from', + ease: 'easeOutQuad', + delay, + }; + const childrenAnim = { ...liAnim, x: '+=10', delay: delay + 100 }; + clearFloatNum += item.md; + clearFloatNum = clearFloatNum > 24 ? 0 : clearFloatNum; + return ( + + + img + +
+ + {childObj.title.children} + + + {childObj.content.children} + +
+
+ ); + }); + return ( +
+
+
+ {dataSource.titleWrapper.children.map(getChildrenToRender)} +
+ + + + {children} + + + +
+
+ ); + } +} + +export default Content3; diff --git a/client/src/landing/Content4.jsx b/client/src/landing/Content4.jsx new file mode 100644 index 000000000..836ca4d14 --- /dev/null +++ b/client/src/landing/Content4.jsx @@ -0,0 +1,59 @@ +import React from 'react'; +import TweenOne from 'rc-tween-one'; +import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; +import VideoPlay from 'react-sublime-video'; +import { getChildrenToRender } from './utils'; + +function Content4(props) { + const { ...tagProps } = props; + const { dataSource, isMobile } = tagProps; + delete tagProps.dataSource; + delete tagProps.isMobile; + const animation = { + y: '+=30', + opacity: 0, + type: 'from', + ease: 'easeOutQuad', + }; + const videoChildren = dataSource.video.children.video; + const videoNameArray = videoChildren.split('.'); + const type = videoNameArray[videoNameArray.length - 1]; + return ( +
+
+
+ {dataSource.titleWrapper.children.map(getChildrenToRender)} +
+ + + {isMobile ? ( + + ) : ( + + + + )} + + +
+
+ ); +} + +export default Content4; diff --git a/client/src/landing/Footer1.jsx b/client/src/landing/Footer1.jsx new file mode 100644 index 000000000..fe64b1219 --- /dev/null +++ b/client/src/landing/Footer1.jsx @@ -0,0 +1,69 @@ +import React from 'react'; +import TweenOne from 'rc-tween-one'; +import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; +import QueueAnim from 'rc-queue-anim'; +import { Row, Col } from 'antd'; +import { getChildrenToRender } from './utils'; +import { isImg } from './utils'; + +class Footer extends React.Component { + static defaultProps = { + className: 'footer1', + }; + + getLiChildren = (data) => + data.map((item, i) => { + const { title, childWrapper, ...itemProps } = item; + return ( + +

+ {typeof title.children === 'string' && + title.children.match(isImg) ? ( + img + ) : ( + title.children + )} +

+
+ {childWrapper.children.map(getChildrenToRender)} +
+ + ); + }); + + render() { + const { ...props } = this.props; + const { dataSource } = props; + delete props.dataSource; + delete props.isMobile; + const childrenToRender = this.getLiChildren(dataSource.block.children); + return ( +
+ + + {childrenToRender} + + +
+
+ {dataSource.copyright.children} +
+
+
+
+
+ ); + } +} + +export default Footer; diff --git a/client/src/landing/Nav0.jsx b/client/src/landing/Nav0.jsx new file mode 100644 index 000000000..fdad914ed --- /dev/null +++ b/client/src/landing/Nav0.jsx @@ -0,0 +1,135 @@ +import React from 'react'; +import TweenOne from 'rc-tween-one'; +import { Menu } from 'antd'; +import { getChildrenToRender } from './utils'; + +const { Item, SubMenu } = Menu; + +class Header extends React.Component { + constructor(props) { + super(props); + this.state = { + phoneOpen: undefined, + }; + } + + phoneClick = () => { + const phoneOpen = !this.state.phoneOpen; + this.setState({ + phoneOpen, + }); + }; + + render() { + const { dataSource, isMobile, ...props } = this.props; + const { phoneOpen } = this.state; + const navData = dataSource.Menu.children; + const navChildren = navData.map((item) => { + const { children: a, subItem, ...itemProps } = item; + if (subItem) { + return ( + + {a.children.map(getChildrenToRender)} +
+ } + popupClassName="header0-item-child" + > + {subItem.map(($item, ii) => { + const { children: childItem } = $item; + const child = childItem.href ? ( + + {childItem.children.map(getChildrenToRender)} + + ) : ( +
+ {childItem.children.map(getChildrenToRender)} +
+ ); + return ( + + {child} + + ); + })} + + ); + } + return ( + + + {a.children.map(getChildrenToRender)} + + + ); + }); + const moment = phoneOpen === undefined ? 300 : null; + return ( + +
+ + img + + {isMobile && ( +
{ + this.phoneClick(); + }} + > + + + +
+ )} + { + if (this.state.phoneOpen) { + e.target.style.height = 'auto'; + } + }, + ease: 'easeInOutQuad', + } + : null + } + moment={moment} + reverse={!!phoneOpen} + > + + {navChildren} + + +
+
+ ); + } +} + +export default Header; diff --git a/client/src/landing/Pricing1.jsx b/client/src/landing/Pricing1.jsx new file mode 100644 index 000000000..f74dcf901 --- /dev/null +++ b/client/src/landing/Pricing1.jsx @@ -0,0 +1,73 @@ +import React from 'react'; +import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; +import QueueAnim from 'rc-queue-anim'; +import { Row, Col, Button } from 'antd'; +import { getChildrenToRender } from './utils'; + +class Pricing1 extends React.PureComponent { + getChildrenToRender = (item) => { + const { + wrapper, + topWrapper, + name, + buttonWrapper, + line, + content, + money, + } = item.children; + return ( + + +
+
+ {name.children} +
+

+ {money.children} +

+
+
+ {content.children} +
+ +
+ +
+
+ + ); + }; + + render() { + const { ...props } = this.props; + const { dataSource } = props; + delete props.dataSource; + delete props.isMobile; + const { block } = dataSource; + const childrenToRender = block.children.map(this.getChildrenToRender); + return ( +
+
+
+ {dataSource.titleWrapper.children.map(getChildrenToRender)} +
+ + + {childrenToRender} + + +
+
+ ); + } +} + +export default Pricing1; diff --git a/client/src/landing/Pricing2.jsx b/client/src/landing/Pricing2.jsx new file mode 100644 index 000000000..31eb70548 --- /dev/null +++ b/client/src/landing/Pricing2.jsx @@ -0,0 +1,114 @@ +import React from 'react'; +import OverPack from 'rc-scroll-anim/lib/ScrollOverPack'; +import QueueAnim from 'rc-queue-anim'; +import { Table } from 'antd'; +import { getChildrenToRender, isImg } from './utils'; + +class Pricing2 extends React.PureComponent { + getColumns = (columns) => { + return columns.map((item) => { + const { childWrapper, ...$item } = item; + return { + align: 'center', + ...$item, + title: ( +
+ {childWrapper.children.map(getChildrenToRender)} +
+ ), + }; + }); + }; + + getDataSource = (dataSource, columns) => + dataSource.map((item, i) => { + const obj = { key: i.toString() }; + item.children.forEach(($item, ii) => { + if (columns[ii]) { + obj[columns[ii].key] = ( +
+ {typeof $item.children === 'string' && + $item.children.match(isImg) ? ( + img + ) : ( + $item.children + )} +
+ ); + } + }); + return obj; + }); + + getMobileChild = (table) => { + const { columns, dataSource, ...tableProps } = table; + const names = columns.children.filter( + (item) => item.key.indexOf('name') >= 0 + ); + const newColumns = columns.children.filter( + (item) => item.key.indexOf('name') === -1 + ); + return newColumns.map((item, i) => { + const items = [].concat(names[0], item).filter((c) => c); + if (items.length > 1) { + items[0].colSpan = 0; + items[1].colSpan = 2; + } + const dataSources = dataSource.children.map(($item) => { + const child = $item.children.filter( + (c) => c.name.indexOf('name') === -1 + ); + const n = $item.children.filter((c) => c.name.indexOf('name') >= 0); + return { + ...$item, + children: [].concat(n[0], child[i]).filter((c) => c), + }; + }); + const props = { + ...tableProps, + columns: this.getColumns(items), + dataSource: this.getDataSource(dataSources, items), + }; + return ( + + ); + }); + }; + + render() { + const { dataSource, isMobile, ...props } = this.props; + const { Table: table, wrapper, page, titleWrapper } = dataSource; + const { columns, dataSource: tableData, ...$table } = table; + const tableProps = { + ...$table, + columns: this.getColumns(columns.children), + dataSource: this.getDataSource(tableData.children, columns.children), + }; + const childrenToRender = isMobile ? ( + this.getMobileChild(table) + ) : ( +
+ ); + return ( +
+
+
+ {titleWrapper.children.map(getChildrenToRender)} +
+ + + {childrenToRender} + + +
+
+ ); + } +} + +export default Pricing2; diff --git a/client/src/landing/data.source.js b/client/src/landing/data.source.js new file mode 100644 index 000000000..ba003460f --- /dev/null +++ b/client/src/landing/data.source.js @@ -0,0 +1,1070 @@ +import React from "react"; +import i18n from "../translations/i18n"; +import ImexOnlineLogoLight from "../assets/ImEX Online Logo.png"; +import ImexOnlineLogoDark from "../assets/ImEX Online Logo - Dark.png"; +import ImexOnlineBannerLogo from "../assets/banner-logo.png"; +import TechnologySvg from "../assets/icons/technology.svg"; +export const Nav00DataSource = { + wrapper: { className: "header0 home-page-wrapper" }, + page: { className: "home-page" }, + logo: { + className: "header0-logo", + children: ImexOnlineLogoLight, + }, + Menu: { + className: "header0-menu", + children: [ + // { + // name: "item0", + // className: "header0-item", + // children: { + // href: "#", + // children: [{ children: "导航一", name: "text" }], + // }, + // subItem: [ + // { + // name: "sub0", + // className: "item-sub", + // children: { + // className: "item-sub-item", + // children: [ + // { + // name: "image0", + // className: "item-image", + // children: + // "https://gw.alipayobjects.com/zos/rmsportal/ruHbkzzMKShUpDYMEmHM.svg", + // }, + // { + // name: "title", + // className: "item-title", + // children: "Ant Design", + // }, + // { + // name: "content", + // className: "item-content", + // children: "企业级 UI 设计体系", + // }, + // ], + // }, + // }, + // { + // name: "sub1", + // className: "item-sub", + // children: { + // className: "item-sub-item", + // children: [ + // { + // name: "image0", + // className: "item-image", + // children: + // "https://gw.alipayobjects.com/zos/rmsportal/ruHbkzzMKShUpDYMEmHM.svg", + // }, + // { + // name: "title", + // className: "item-title", + // children: "Ant Design", + // }, + // { + // name: "content", + // className: "item-content", + // children: "企业级 UI 设计体系", + // }, + // ], + // }, + // }, + // ], + // }, + { + name: "item1", + className: "header0-item", + children: { + href: "#", + children: [ + { children: i18n.t("landing.labels.features"), name: "text" }, + ], + }, + }, + { + name: "item2", + className: "header0-item", + children: { + href: "#", + children: [ + { children: i18n.t("landing.labels.pricing"), name: "text" }, + ], + }, + }, + { + name: "item3", + className: "header0-item", + children: { + href: "/manage", + children: [ + { children: i18n.t("landing.labels.managemyshop"), name: "text" }, + ], + }, + }, + ], + }, + mobileMenu: { className: "header0-mobile-menu" }, +}; +export const Banner00DataSource = { + wrapper: { className: "banner0" }, + textWrapper: { className: "banner0-text-wrapper" }, + title: { + className: "banner0-title", + children: ( + + ), + }, + content: { + className: "banner0-content", + children: i18n.t("landing.hero.title"), + }, + button: { + className: "banner0-button", + children: i18n.t("landing.hero.button"), + }, +}; +export const Content40DataSource = { + wrapper: { className: "home-page-wrapper content4-wrapper" }, + page: { className: "home-page content4" }, + OverPack: { playScale: 0.3, className: "" }, + titleWrapper: { + className: "title-wrapper", + children: [ + { + name: "title", + children: "蚂蚁金融云提供专业的服务", + className: "title-h1", + }, + { + name: "content", + className: "title-content content4-title-content", + children: "科技想象力,金融创造力", + }, + ], + }, + video: { + className: "content4-video", + children: { + video: "https://os.alipayobjects.com/rmsportal/EejaUGsyExkXyXr.mp4", + image: "https://zos.alipayobjects.com/rmsportal/HZgzhugQZkqUwBVeNyfz.jpg", + }, + }, +}; +export const Content00DataSource = { + wrapper: { className: "home-page-wrapper content0-wrapper" }, + page: { className: "home-page content0" }, + OverPack: { playScale: 0.3, className: "" }, + titleWrapper: { + className: "title-wrapper", + children: [{ name: "title", children: "Feature Highlights" }], + }, + childWrapper: { + className: "content0-block-wrapper", + children: [ + { + name: "block0", + className: "content0-block", + md: 8, + xs: 24, + children: { + className: "content0-block-item", + children: [ + { + name: "image", + className: "content0-block-icon", + children: + "https://zos.alipayobjects.com/rmsportal/WBnVOjtIlGWbzyQivuyq.png", + }, + { + name: "title", + className: "content0-block-title", + children: "Feature Highlight 1", + }, + { name: "content", children: "Feature description for this item." }, + ], + }, + }, + { + name: "block1", + className: "content0-block", + md: 8, + xs: 24, + children: { + className: "content0-block-item", + children: [ + { + name: "image", + className: "content0-block-icon", + children: + "https://zos.alipayobjects.com/rmsportal/YPMsLQuCEXtuEkmXTTdk.png", + }, + { + name: "title", + className: "content0-block-title", + children: "Feature Highlight 2", + }, + { + name: "content", + children: "Feature description for #2", + }, + ], + }, + }, + { + name: "block2", + className: "content0-block", + md: 8, + xs: 24, + children: { + className: "content0-block-item", + children: [ + { + name: "image", + className: "content0-block-icon", + children: + "https://zos.alipayobjects.com/rmsportal/EkXWVvAaFJKCzhMmQYiX.png", + }, + { + name: "title", + className: "content0-block-title", + children: "Feature Highlight 3", + }, + { + name: "content", + children: "Feature description for 3.", + }, + ], + }, + }, + ], + }, +}; +export const Content10DataSource = { + wrapper: { className: "home-page-wrapper content1-wrapper" }, + OverPack: { className: "home-page content1", playScale: 0.3 }, + imgWrapper: { className: "content1-img", md: 10, xs: 24 }, + img: { + children: TechnologySvg, + }, + textWrapper: { className: "content1-text", md: 14, xs: 24 }, + title: { + className: "content1-title", + children: i18n.t("landing.bigfeature.title"), + }, + content: { + className: "content1-content", + children: i18n.t("landing.bigfeature.subtitle"), + }, +}; +export const Pricing20DataSource = { + wrapper: { className: "home-page-wrapper pricing2-wrapper" }, + page: { className: "home-page pricing2" }, + OverPack: { playScale: 0.3, className: "pricing2-content-wrapper" }, + titleWrapper: { + className: "pricing2-title-wrapper", + children: [ + { + name: "title", + children: i18n.t("landing.pricing.pricingtitle"), + className: "pricing2-title-h1", + }, + ], + }, + Table: { + name: "tabsTitle", + size: "default", + className: "pricing2-table", + columns: { + children: [ + { + dataIndex: "name", + key: "name", + name: "empty", + childWrapper: { + children: [ + { name: "name", children: " " }, + { name: "content", children: " " }, + ], + }, + }, + { + dataIndex: "essentials", + key: "essentials", + name: "essentials", + childWrapper: { + className: "pricing2-table-name-block", + children: [ + { + name: "name", + className: "pricing2-table-name", + children: i18n.t("landing.pricing.essentials.name"), + }, + { + name: "content", + className: "pricing2-table-money", + children: i18n.t("landing.pricing.essentials.sub"), + }, + // { name: "button", children: { href: "#", children: "免费试用" } }, + ], + }, + }, + { + dataIndex: "basic", + key: "basic", + name: "basic", + childWrapper: { + className: "pricing2-table-name-block", + children: [ + { + name: "name", + className: "pricing2-table-name", + children: i18n.t("landing.pricing.basic.name"), + }, + { + name: "content", + className: "pricing2-table-money", + children: i18n.t("landing.pricing.basic.sub"), + }, + //{ name: "button", children: { href: "#", children: "立即购买" } }, + ], + }, + }, + { + dataIndex: "pro", + key: "pro", + name: "pro", + childWrapper: { + className: "pricing2-table-name-block", + children: [ + { + name: "name", + className: "pricing2-table-name", + children: i18n.t("landing.pricing.pro.name"), + }, + { + name: "content", + className: "pricing2-table-money", + children: i18n.t("landing.pricing.pro.sub"), + }, + // { + // name: "button", + // children: { href: "#", type: "primary", children: "立即购买" }, + // }, + ], + }, + }, + { + dataIndex: "unlimited", + key: "unlimited", + name: "unlimited", + childWrapper: { + className: "pricing2-table-name-block", + children: [ + { + name: "name", + className: "pricing2-table-name", + children: i18n.t("landing.pricing.unlimited.name"), + }, + { + name: "content", + className: "pricing2-table-money", + children: i18n.t("landing.pricing.unlimited.sub"), + }, + // { name: "button", children: { href: "#", children: "立即购买" } }, + ], + }, + }, + ], + }, + dataSource: { + children: [ + { + name: "list0", + children: [ + { + className: "pricing2-table-content-name", + name: "name", + children: "Unlimited Vehicles, Customers, and Work Orders", + }, + { + children: + "https://gw.alipayobjects.com/zos/basement_prod/14ce3060-34e6-4b30-9a45-1a6b95542310.svg", + name: "content0", + className: "pricing2-table-content", + }, + { + children: + "https://gw.alipayobjects.com/zos/basement_prod/14ce3060-34e6-4b30-9a45-1a6b95542310.svg", + name: "content1", + className: "pricing2-table-content", + }, + { + children: + "https://gw.alipayobjects.com/zos/basement_prod/14ce3060-34e6-4b30-9a45-1a6b95542310.svg", + name: "content2", + className: "pricing2-table-content", + }, + { + children: + "https://gw.alipayobjects.com/zos/basement_prod/14ce3060-34e6-4b30-9a45-1a6b95542310.svg", + name: "content3", + className: "pricing2-table-content", + }, + ], + }, + { + name: "list1", + children: [ + { + className: "pricing2-table-content-name", + name: "name", + children: + "Access your system from anywhere (Desktop, Mobile, and Native Mobile Apps)", + }, + { + children: + "https://gw.alipayobjects.com/zos/basement_prod/14ce3060-34e6-4b30-9a45-1a6b95542310.svg", + name: "content0", + className: "pricing2-table-content", + }, + { + children: + "https://gw.alipayobjects.com/zos/basement_prod/14ce3060-34e6-4b30-9a45-1a6b95542310.svg", + name: "content1", + className: "pricing2-table-content", + }, + { + children: + "https://gw.alipayobjects.com/zos/basement_prod/14ce3060-34e6-4b30-9a45-1a6b95542310.svg", + name: "content2", + className: "pricing2-table-content", + }, + { + children: + "https://gw.alipayobjects.com/zos/basement_prod/14ce3060-34e6-4b30-9a45-1a6b95542310.svg", + name: "content3", + className: "pricing2-table-content", + }, + ], + }, + { + name: "list2", + children: [ + { + className: "pricing2-table-content-name", + name: "name", + children: "Included Media Storage", + }, + { + name: "content0", + children: "50GB", + className: "pricing2-table-content", + }, + { + name: "content1", + children: "100GB", + className: "pricing2-table-content", + }, + { + name: "content2", + children: "175GB", + className: "pricing2-table-content", + }, + { + name: "content3", + children: "250GB", + className: "pricing2-table-content", + }, + ], + }, + { + name: "list3", + children: [ + { + className: "pricing2-table-content-name", + name: "name", + children: "Mobile Image Sync", + }, + { + children: "-", + name: "content0", + className: "pricing2-table-content", + }, + { + name: "content1", + children: "-", + className: "pricing2-table-content", + }, + { + name: "content2", + children: + "https://gw.alipayobjects.com/zos/basement_prod/14ce3060-34e6-4b30-9a45-1a6b95542310.svg", + className: "pricing2-table-content", + }, + { + name: "content3", + children: + "https://gw.alipayobjects.com/zos/basement_prod/14ce3060-34e6-4b30-9a45-1a6b95542310.svg", + className: "pricing2-table-content", + }, + ], + }, + { + name: "list4", + children: [ + { + className: "pricing2-table-content-name", + name: "name", + children: "Integrated Text Messaging", + }, + { + name: "content0", + children: "-", + className: "pricing2-table-content", + }, + { + name: "content1", + children: "-", + className: "pricing2-table-content", + }, + { + name: "content2", + children: + "https://gw.alipayobjects.com/zos/basement_prod/14ce3060-34e6-4b30-9a45-1a6b95542310.svg", + className: "pricing2-table-content", + }, + { + name: "content3", + children: + "https://gw.alipayobjects.com/zos/basement_prod/14ce3060-34e6-4b30-9a45-1a6b95542310.svg", + className: "pricing2-table-content", + }, + ], + }, + { + name: "list5", + children: [ + { + className: "pricing2-table-content-name", + name: "name", + children: "Integrated CSI", + }, + { + name: "content0", + children: "-", + className: "pricing2-table-content", + }, + { + name: "content1", + children: "-", + className: "pricing2-table-content", + }, + { + name: "content2", + children: "-", + className: "pricing2-table-content", + }, + { + name: "content3", + children: + "https://gw.alipayobjects.com/zos/basement_prod/14ce3060-34e6-4b30-9a45-1a6b95542310.svg", + className: "pricing2-table-content", + }, + ], + }, + ], + }, + }, +}; + +export const Pricing11DataSource = { + wrapper: { className: "home-page-wrapper pricing1-wrapper" }, + page: { className: "home-page pricing1" }, + OverPack: { playScale: 0.3, className: "pricing1-content-wrapper" }, + titleWrapper: { + className: "pricing1-title-wrapper", + children: [ + { name: "title", children: "价目表", className: "pricing1-title-h1" }, + ], + }, + block: { + className: "pricing1-block-wrapper", + children: [ + { + name: "block0", + className: "pricing1-block", + md: 8, + xs: 24, + children: { + wrapper: { className: "pricing1-block-box " }, + topWrapper: { className: "pricing1-top-wrapper" }, + name: { className: "pricing1-name", children: "Free" }, + money: { className: "pricing1-money", children: "¥0" }, + content: { + className: "pricing1-content", + children: ( + + 140-500Mbps +
140 GB-50TB(含) +
14500GB流量包 +
14国内按峰值宽带账单 +
14弹性计算 +
14云服务器 ECS{" "} +
+ ), + }, + line: { className: "pricing1-line" }, + buttonWrapper: { + className: "pricing1-button-wrapper", + children: { + a: { + className: "pricing1-button", + href: "#", + children: "免费试用", + }, + }, + }, + }, + }, + { + name: "block1", + className: "pricing1-block", + md: 8, + xs: 24, + children: { + wrapper: { className: "pricing1-block-box active" }, + topWrapper: { className: "pricing1-top-wrapper" }, + name: { className: "pricing1-name", children: "Starter" }, + money: { className: "pricing1-money", children: "¥199" }, + content: { + className: "pricing1-content", + children: ( + + 14500-5Gbps +
+ 1410 GB-50TB(含) +
+ 141TB流量包 +
+ 14国内按峰值宽带账单 +
+ 14弹性计算 +
+ 云服务器 ECS +
+ ), + }, + line: { className: "pricing1-line" }, + buttonWrapper: { + className: "pricing1-button-wrapper", + children: { + a: { + className: "pricing1-button", + href: "#", + children: "立即购买", + }, + }, + }, + }, + }, + { + name: "block2", + className: "pricing1-block", + md: 8, + xs: 24, + children: { + wrapper: { className: "pricing1-block-box " }, + topWrapper: { className: "pricing1-top-wrapper" }, + name: { className: "pricing1-name", children: "Pro" }, + money: { className: "pricing1-money", children: "¥999" }, + content: { + className: "pricing1-content", + children: ( + + 14大于5Gbps +
+ 1450 GB-100TB(含) +
+ 145TB流量包 +
+ 14国内按峰值宽带账单 +
+ 14弹性计算 +
+ 14云服务器 ECS +
+ ), + }, + line: { className: "pricing1-line" }, + buttonWrapper: { + className: "pricing1-button-wrapper", + children: { + a: { + className: "pricing1-button", + href: "#", + children: "立即购买", + }, + }, + }, + }, + }, + ], + }, +}; +export const Content30DataSource = { + wrapper: { className: "home-page-wrapper content3-wrapper" }, + page: { className: "home-page content3" }, + OverPack: { playScale: 0.3 }, + titleWrapper: { + className: "title-wrapper", + children: [ + { + name: "title", + children: "蚂蚁金融云提供专业的服务", + className: "title-h1", + }, + { + name: "content", + className: "title-content", + children: "基于阿里云强大的基础资源", + }, + ], + }, + block: { + className: "content3-block-wrapper", + children: [ + { + name: "block0", + className: "content3-block", + md: 8, + xs: 24, + children: { + icon: { + className: "content3-icon", + children: + "https://zos.alipayobjects.com/rmsportal/ScHBSdwpTkAHZkJ.png", + }, + textWrapper: { className: "content3-text" }, + title: { className: "content3-title", children: "企业资源管理" }, + content: { + className: "content3-content", + children: + "云资源集中编排、弹性伸缩、持续发布和部署,高可用及容灾。", + }, + }, + }, + { + name: "block1", + className: "content3-block", + md: 8, + xs: 24, + children: { + icon: { + className: "content3-icon", + children: + "https://zos.alipayobjects.com/rmsportal/NKBELAOuuKbofDD.png", + }, + textWrapper: { className: "content3-text" }, + title: { className: "content3-title", children: "云安全" }, + content: { + className: "content3-content", + children: + "按金融企业安全要求打造的完整云上安全体系,全方位保障金融应用及数据安全。", + }, + }, + }, + { + name: "block2", + className: "content3-block", + md: 8, + xs: 24, + children: { + icon: { + className: "content3-icon", + children: + "https://zos.alipayobjects.com/rmsportal/xMSBjgxBhKfyMWX.png", + }, + textWrapper: { className: "content3-text" }, + title: { className: "content3-title", children: "云监控" }, + content: { + className: "content3-content", + children: + "分布式云环境集中监控,统一资源及应用状态视图,智能分析及故障定位。", + }, + }, + }, + { + name: "block3", + className: "content3-block", + md: 8, + xs: 24, + children: { + icon: { + className: "content3-icon", + children: + "https://zos.alipayobjects.com/rmsportal/MNdlBNhmDBLuzqp.png", + }, + textWrapper: { className: "content3-text" }, + title: { className: "content3-title", children: "移动" }, + content: { + className: "content3-content", + children: + "一站式移动金融APP开发及全面监控;丰富可用组件,动态发布和故障热修复。", + }, + }, + }, + { + name: "block4", + className: "content3-block", + md: 8, + xs: 24, + children: { + icon: { + className: "content3-icon", + children: + "https://zos.alipayobjects.com/rmsportal/UsUmoBRyLvkIQeO.png", + }, + textWrapper: { className: "content3-text" }, + title: { className: "content3-title", children: "分布式中间件" }, + content: { + className: "content3-content", + children: + "金融级联机交易处理中间件,大规模分布式计算机,数万笔/秒级并发能力,严格保证交易数据统一性。", + }, + }, + }, + { + name: "block5", + className: "content3-block", + md: 8, + xs: 24, + children: { + icon: { + className: "content3-icon", + children: + "https://zos.alipayobjects.com/rmsportal/ipwaQLBLflRfUrg.png", + }, + textWrapper: { className: "content3-text" }, + title: { className: "content3-title", children: "大数据" }, + content: { + className: "content3-content", + children: + "一站式、全周期大数据协同工作平台,PB级数据处理、毫秒级数据分析工具。", + }, + }, + }, + ], + }, +}; +export const Content120DataSource = { + wrapper: { className: "home-page-wrapper content12-wrapper" }, + page: { className: "home-page content12" }, + OverPack: { playScale: 0.3, className: "" }, + titleWrapper: { + className: "title-wrapper", + children: [ + { + name: "image", + children: + "https://gw.alipayobjects.com/zos/rmsportal/PiqyziYmvbgAudYfhuBr.svg", + className: "title-image", + }, + { name: "title", children: "特别鸣谢", className: "title-h1" }, + ], + }, + block: { + className: "img-wrapper", + children: [ + { + name: "block0", + className: "block", + md: 8, + xs: 24, + children: { + wrapper: { className: "block-content" }, + img: { + children: + "https://gw.alipayobjects.com/zos/rmsportal/TFicUVisNHTOEeMYXuQF.svg", + }, + }, + }, + { + name: "block1", + className: "block", + md: 8, + xs: 24, + children: { + wrapper: { className: "block-content" }, + img: { + children: + "https://gw.alipayobjects.com/zos/rmsportal/hkLGkrlCEkGZeMQlnEkD.svg", + }, + }, + }, + { + name: "block2", + className: "block", + md: 8, + xs: 24, + children: { + wrapper: { className: "block-content" }, + img: { + children: + "https://gw.alipayobjects.com/zos/rmsportal/bqyPRSZmhvrsfJrBvASi.svg", + }, + }, + }, + { + name: "block3", + className: "block", + md: 8, + xs: 24, + children: { + wrapper: { className: "block-content" }, + img: { + children: + "https://gw.alipayobjects.com/zos/rmsportal/UcsyszzOabdCYDkoPPnM.svg", + }, + }, + }, + { + name: "block4", + className: "block", + md: 8, + xs: 24, + children: { + wrapper: { className: "block-content" }, + img: { + children: + "https://gw.alipayobjects.com/zos/rmsportal/kRBeaICGexAmVjqBEqgw.svg", + }, + }, + }, + { + name: "block5", + className: "block", + md: 8, + xs: 24, + children: { + wrapper: { className: "block-content" }, + img: { + children: + "https://gw.alipayobjects.com/zos/rmsportal/ftBIiyJcCHpHEioRvPsV.svg", + }, + }, + }, + ], + }, +}; +export const Footer10DataSource = { + wrapper: { className: "home-page-wrapper footer1-wrapper" }, + OverPack: { className: "footer1", playScale: 0.2 }, + block: { + className: "home-page", + gutter: 0, + children: [ + { + name: "block0", + xs: 24, + md: 6, + className: "block", + title: { + className: "logo", + children: ( + + ), + }, + childWrapper: { + className: "slogan", + children: [ + { + name: "content0", + children: i18n.t("landing.footer.slogan"), + }, + ], + }, + }, + // { + // name: "block1", + // xs: 24, + // md: 6, + // className: "block", + // title: { children: "产品" }, + // childWrapper: { + // children: [ + // { name: "link0", href: "#", children: "产品更新记录" }, + // { name: "link1", href: "#", children: "API文档" }, + // { name: "link2", href: "#", children: "快速入门" }, + // { name: "link3", href: "#", children: "参考指南" }, + // ], + // }, + // }, + { + name: "block2", + xs: 24, + md: 6, + className: "block", + title: { children: i18n.t("landing.footer.io.name") }, + childWrapper: { + children: [ + { + href: "https://help.imex.online", + name: "link0", + children: i18n.t("landing.footer.io.help"), + }, + { + href: "https://status.imex.online", + name: "link1", + children: i18n.t("landing.footer.io.status"), + }, + ], + }, + }, + { + name: "block3", + xs: 24, + md: 6, + className: "block", + title: { children: i18n.t("landing.footer.company.name") }, + childWrapper: { + children: [ + { + href: "/privacy", + name: "link0", + children: i18n.t("landing.footer.company.privacypolicy"), + }, + { + href: "/about", + name: "link1", + children: i18n.t("landing.footer.company.about"), + }, + { + href: "/disclaimer", + name: "link2", + children: i18n.t("landing.footer.company.disclaimers"), + }, + { + href: "https://thinkimex.com", + name: "link3", + children: i18n.t("landing.footer.company.contact"), + }, + ], + }, + }, + ], + }, + copyrightWrapper: { className: "copyright-wrapper" }, + copyrightPage: { className: "home-page" }, + copyright: { + className: "copyright", + children: ( + + ©2021 ImEX Systems used under + license. + + ), + }, +}; diff --git a/client/src/landing/documentation.md b/client/src/landing/documentation.md new file mode 100644 index 000000000..ad58ffcce --- /dev/null +++ b/client/src/landing/documentation.md @@ -0,0 +1,4 @@ +# 如何使用: + +- umi 里如何使用[请查看](https://landing.ant.design/docs/use/umi)。 +- 其它脚手架使用[请查看](https://landing.ant.design/docs/use/getting-started)。 diff --git a/client/src/landing/index.jsx b/client/src/landing/index.jsx new file mode 100644 index 000000000..420629bd1 --- /dev/null +++ b/client/src/landing/index.jsx @@ -0,0 +1,139 @@ +/* eslint no-undef: 0 */ +/* eslint arrow-parens: 0 */ +import { enquireScreen } from "enquire-js"; +import React from "react"; +import Banner0 from "./Banner0"; +// import Content4 from "./Content4"; +import Content0 from "./Content0"; +import Content1 from "./Content1"; +import { + Banner00DataSource, + // Content40DataSource, + Content00DataSource, + Content10DataSource, + // Pricing11DataSource, + // Content30DataSource, + // Content120DataSource, + Footer10DataSource, + Nav00DataSource, + Pricing20DataSource, +} from "./data.source"; +// import Pricing1 from "./Pricing1"; +// import Content3 from "./Content3"; +// import Content12 from "./Content12"; +import Footer1 from "./Footer1"; +import "./less/antMotionStyle.less"; +import Nav0 from "./Nav0"; +import Pricing2 from "./Pricing2"; + +let isMobile; +enquireScreen((b) => { + isMobile = b; +}); + +const { location = {} } = typeof window !== "undefined" ? window : {}; + +export default class Home extends React.Component { + constructor(props) { + super(props); + this.state = { + isMobile, + show: !location.port, // 如果不是 dva 2.0 请删除 + }; + } + + componentDidMount() { + // 适配手机屏幕; + enquireScreen((b) => { + this.setState({ isMobile: !!b }); + }); + // dva 2.0 样式在组件渲染之后动态加载,导致滚动组件不生效;线上不影响; + /* 如果不是 dva 2.0 请删除 start */ + if (location.port) { + // 样式 build 时间在 200-300ms 之间; + setTimeout(() => { + this.setState({ + show: true, + }); + }, 500); + } + /* 如果不是 dva 2.0 请删除 end */ + } + + render() { + const children = [ + , + , + // , + , + , + , + // , + // , + // , + , + ]; + return ( +
{ + this.dom = d; + }} + > + {/* 如果不是 dva 2.0 替换成 {children} start */} + {this.state.show && children} + {/* 如果不是 dva 2.0 替换成 {children} end */} +
+ ); + } +} diff --git a/client/src/landing/less/antMotionStyle.less b/client/src/landing/less/antMotionStyle.less new file mode 100644 index 000000000..c47700518 --- /dev/null +++ b/client/src/landing/less/antMotionStyle.less @@ -0,0 +1,14 @@ +@import './common.less'; +@import './custom.less'; +@import './content.less'; +@import './nav0.less'; +@import './banner0.less'; +@import './content4.less'; +@import './content0.less'; +@import './content1.less'; +@import './pricing2.less'; +@import './pricing1.less'; +@import './content3.less'; +@import './content12.less'; +@import './footer1.less'; +@import './edit.less'; \ No newline at end of file diff --git a/client/src/landing/less/banner0.less b/client/src/landing/less/banner0.less new file mode 100644 index 000000000..ad3fe7281 --- /dev/null +++ b/client/src/landing/less/banner0.less @@ -0,0 +1,84 @@ +@banner0: banner0; +.@{banner0} { + // 如果在第一屏且导航位置为 relative, 一屏为 height: calc(~"100vh - 64px"); + width: 100%; + height: 100vh; + position: relative; + text-align: center; + border-color: #666; + background-image: url("../../assets/banner3.jpeg"); + background-size: cover; + background-attachment: fixed; + background-position: center; + & &-text-wrapper { + display: inline-block; + position: absolute; + top: 20%; + margin: auto; + left: 0; + right: 0; + font-size: 14px; + color: @template-text-color-light; + width: 550px; + > .queue-anim-leaving { + position: relative !important; + } + } + & &-title { + width: 350px; + //left: 30px; + min-height: 60px; + margin: auto; + display: inline-block; + font-size: 40px; + position: relative; + } + & &-content { + margin-bottom: 20px; + word-wrap: break-word; + min-height: 24px; + } + & &-button { + border: 1px solid #fff; + color: #fff; + background: transparent; + box-shadow: 0 0 0 transparent; + font-size: 16px; + height: 40px; + transition: background 0.45s @ease-out, box-shadow 0.45s @ease-out; + &:hover { + color: #fff; + border-color: #fff; + background: rgba(255, 255, 255, 0.1); + box-shadow: 0 0 10px rgba(50, 250, 255, 0.75); + } + &:focus { + color: #fff; + border-color: #fff; + } + &.queue-anim-leaving { + width: auto; + } + } + & &-icon { + bottom: 20px; + font-size: 24px; + position: absolute; + left: 50%; + margin-left: -12px; + color: @template-text-color-light; + } +} + +@media screen and (max-width: 767px) { + .@{banner0} { + background-attachment: inherit; + & &-text-wrapper { + width: 90%; + } + & &-title { + width: 90%; + left: 0; + } + } +} diff --git a/client/src/landing/less/common.less b/client/src/landing/less/common.less new file mode 100644 index 000000000..a0ca2a04c --- /dev/null +++ b/client/src/landing/less/common.less @@ -0,0 +1,42 @@ + +// @import "~antd/lib/style/v2-compatible-reset.less"; + +body { + word-wrap: break-word; +} + +body, +div, +dl, +dt, +dd, +ul, +ol, +li, +h1, +h2, +h3, +h4, +h5, +h6 { + margin: 0; + padding: 0; +} + +/* .content-wrapper > .tween-one-leaving, +.queue-anim-leaving { + // position: absolute !important; + // width: 100%; +} */ + +.video { + max-width: 800px; +} + +#react-content { + min-height: 100%; +} +.home-page-wrapper p { + padding: 0; + margin: 0; +} diff --git a/client/src/landing/less/content.less b/client/src/landing/less/content.less new file mode 100644 index 000000000..c5ebf367c --- /dev/null +++ b/client/src/landing/less/content.less @@ -0,0 +1,44 @@ +@homepage: home-page; +.@{homepage}-wrapper { + width: 100%; + position: relative; + overflow: hidden; + .@{homepage} { + height: 100%; + max-width: 1200px; + position: relative; + margin: auto; + will-change: transform; + } + .title-wrapper > h1, > h1 { + font-size: 32px; + color: @text-color; + margin-bottom: 16px; + } + .title-wrapper { + margin: 0 auto 64px; + text-align: center; + } +} + +.@{homepage} { + padding: 128px 24px; +} + +@media screen and (max-width: 767px) { + .@{homepage}-wrapper { + .@{homepage} { + padding: 56px 24px; + >h1 { + font-size: 24px; + margin: 0 auto 32px; + &.title-h1 { + margin-bottom: 8px; + } + } + >p { + margin-bottom: 32px; + } + } + } +} diff --git a/client/src/landing/less/content0.less b/client/src/landing/less/content0.less new file mode 100644 index 000000000..0a97b2ef5 --- /dev/null +++ b/client/src/landing/less/content0.less @@ -0,0 +1,55 @@ +@content0: content0; + +.@{content0}-wrapper { + min-height: 446px; + overflow: hidden; + + .@{content0} { + height: 100%; + padding: 64px 24px; + + >.title-wrapper { + margin: 0 auto 48px; + } + + &-block { + padding: 0 4%; + display: inline-block; + text-align: center; + min-height: 200px; + margin-bottom: 24px; + img { + width: 100%; + } + + &-wrapper { + position: relative; + height: 100%; + top: 25%; + padding: 20px 0; + } + + &.queue-anim-leaving { + position: relative !important; + } + + &-icon { + width: 100px; + height: 100px; + margin: auto; + } + + &-title { + line-height: 32px; + margin: 10px auto; + font-size: 24px; + } + } + } +} + +@media screen and (max-width: 767px) { + .@{content0}-wrapper { + min-height: 880px; + } +} diff --git a/client/src/landing/less/content1.less b/client/src/landing/less/content1.less new file mode 100644 index 000000000..4d03ff366 --- /dev/null +++ b/client/src/landing/less/content1.less @@ -0,0 +1,76 @@ +@content1: content1; +.@{content1}-wrapper { + height: 360px; + .@{content1} { + height: 100%; + padding: 0 24px; + &-img { + height: 100%; + transform-origin: top; + padding: 0 32px; + display: flex; + align-items: center; + justify-content: center; + span { + display: block; + width: 250px; + img { + display: block; + } + } + } + &-text { + padding: 0 32px; + height: 100%; + .@{content1}-content, + .@{content1}-title { + position: relative !important; + } + .@{content1}-title { + font-size: 32px; + font-weight: normal; + color: #404040; + margin-top: 120px; + } + .content { + margin-top: 20px; + } + } + } +} + +@media screen and (max-width: 767px) { + .@{content1}-wrapper { + height: 600px; + .@{content1} { + &-img { + height: 200px; + padding: 0; + text-align: center; + margin-top: 64px; + span { + display: inline-block; + width: 180px; + height: 200px; + line-height: 200px; + margin: auto; + } + } + &-text { + height: auto; + margin-bottom: 20px; + text-align: center; + padding: 0; + .@{content1}-content, + .@{content1}-title { + width: 100%; + top: auto; + } + .@{content1}-title { + margin: 32px auto 16px; + font-size: 24px; + } + } + } + } +} diff --git a/client/src/landing/less/content12.less b/client/src/landing/less/content12.less new file mode 100644 index 000000000..4d4f05f53 --- /dev/null +++ b/client/src/landing/less/content12.less @@ -0,0 +1,52 @@ +@content12: content12; +.@{content12}-wrapper { + background-color: #fafafa; + min-height: 470px; + .@{content12} { + padding: 64px 24px; + >p { + text-align: center; + } + } + .img-wrapper { + margin: 0 auto; + left: 0; + right: 0; + .block { + margin-bottom: 40px; + .block-content { + display: flex; + border-radius: 4px; + text-align: center; + position: relative; + overflow: hidden; + border: none; + height: 64px; + align-items: center; + transition: box-shadow .3s @ease-out, transform .3s @ease-out; + & > span { + width: 100%; + display: block; + } + } + } + } +} + +@media screen and (max-width: 767px) { + .@{content12}-wrapper { + overflow: hidden; + .@{content12} { + ul { + li { + display: block; + width: 100%; + padding: 2%; + span { + height: 168px; + } + } + } + } + } +} diff --git a/client/src/landing/less/content3.less b/client/src/landing/less/content3.less new file mode 100644 index 000000000..24ee0e4f7 --- /dev/null +++ b/client/src/landing/less/content3.less @@ -0,0 +1,52 @@ +@content3: content3; +.@{content3}-wrapper { + min-height: 764px; + .@{content3} { + height: 100%; + overflow: hidden; + & .title-content { + text-align: center; + } + &-block-wrapper { + position: relative; + .@{content3}-block { + display: inline-block; + padding: 48px 24px; + vertical-align: top; + .@{content3}-icon { + display: inline-block; + width: 15%; + vertical-align: top; + } + .@{content3}-text { + width: 85%; + display: inline-block; + padding-left: 8%; + } + &.clear-both { + clear: both; + } + } + } + } +} + +@media screen and (max-width: 767px) { + .@{content3}-wrapper { + min-height: 1080px; + .@{content3} { + &-block-wrapper { + margin: 20px auto; + height: auto; + .@{content3}-block { + .@{content3}-title { + font-size: 20px; + } + &.queue-anim-leaving { + position: relative !important; + } + } + } + } + } +} diff --git a/client/src/landing/less/content4.less b/client/src/landing/less/content4.less new file mode 100644 index 000000000..c700bfb2a --- /dev/null +++ b/client/src/landing/less/content4.less @@ -0,0 +1,37 @@ +@content4: content4; +.@{content4}-wrapper { + min-height: 720px; + background: #fafafa; + .@{content4} { + height: 100%; + overflow: hidden; + &-video { + border-radius: 4px; + overflow: hidden; + max-width: 800px; + margin: auto; + background: #fff; + box-shadow: 0 4px 8px rgba(0, 0, 0, .15); + video { + display: block; + margin: auto; + } + } + } +} + +@media screen and (max-width: 767px) { + .@{content4}-wrapper { + min-height: 350px; + .@{content4} { + overflow: hidden; + width: 90%; + margin: auto; + &-video { + top: 15%; + background: url("https://zos.alipayobjects.com/rmsportal/HZgzhugQZkqUwBVeNyfz.jpg") no-repeat center; + background-size: cover; + } + } + } +} diff --git a/client/src/landing/less/custom.less b/client/src/landing/less/custom.less new file mode 100644 index 000000000..710e47c9d --- /dev/null +++ b/client/src/landing/less/custom.less @@ -0,0 +1,35 @@ +@import "~antd/lib/style/themes/default.less"; + +@line-color: #e9e9e9; + +@shadow-color: rgba(0, 0, 0, 0.15); + +@bottom-bar-bg-color: #262626; +@bottom-bar-line-color: #000; + +@template-bg-color: #001529; +@template-bg-color-light: #ececec; +@template-nav-bg-color: #001529; +@template-text-color: #ccc; +@template-text-title-color: #bcbcbc; +@template-text-color-light: #fff; +@template-footer-text-color: #999; + +@animate-duration: .45s; + +/* 详细页图片或框框的样式; +*/ +.page-shadow() { + box-shadow: 0 5px 8px @shadow-color; +} + +.page-pro() { + border-radius: 6px; + border: 1px solid @line-color; + transform: translateY(0); + transition: transform .3s @ease-out, box-shadow .3s @ease-out; + &:hover { + .page-shadow(); + transform: translateY(-5px); + } +} diff --git a/client/src/landing/less/edit.less b/client/src/landing/less/edit.less new file mode 100644 index 000000000..e69de29bb diff --git a/client/src/landing/less/footer1.less b/client/src/landing/less/footer1.less new file mode 100644 index 000000000..8d8579b8a --- /dev/null +++ b/client/src/landing/less/footer1.less @@ -0,0 +1,98 @@ +.footer1-wrapper { + background: @template-bg-color; + overflow: hidden; + position: relative; + min-height: 360px; + color: @template-footer-text-color; + .footer1 { + .home-page { + padding: 64px 24px 80px; + } + } + .block { + padding: 0 32px; + .logo { + max-width: 180px; + } + .slogan { + font-size: 12px; + margin-top: -20px; + } + >h2 { + margin-bottom: 24px; + color: @template-text-color; + } + a { + color: @template-footer-text-color; + margin-bottom: 12px; + float: left; + clear: both; + &:hover { + color: @primary-color; + } + } + } + .copyright-wrapper { + width: 100%; + border-top: 1px solid fade(@line-color, 10); + .home-page { + padding: 0 24px; + overflow: hidden; + } + .copyright { + height: 80px; + text-align: center; + line-height: 80px; + } + } +} + +@media screen and (max-width: 767px) { + .footer1 { + min-height: 550px; + &-wrapper { + .footer1 { + .home-page { + padding: 64px 24px 32px; + } + } + } + .logo { + margin: 0 auto 24px; + } + .block { + text-align: center; + margin-bottom: 32px; + padding: 0; + } + >ul { + width: 90%; + margin: 20px auto 0; + padding: 10px 0; + >li { + width: 100%; + h2 { + margin-bottom: 10px; + } + li { + display: inline-block; + margin-right: 10px; + } + } + } + .copyright { + &-wrapper { + .home-page { + padding: 0; + .copyright { + font-size: 12px; + } + } + } + + span { + width: 90%; + } + } + } +} diff --git a/client/src/landing/less/nav0.less b/client/src/landing/less/nav0.less new file mode 100644 index 000000000..3c662defc --- /dev/null +++ b/client/src/landing/less/nav0.less @@ -0,0 +1,187 @@ +@header0: header0; + +.@{header0} { + background: @template-nav-bg-color; + width: 100%; + z-index: 1; + box-shadow: 0 5px 8px fade(#000, 15); + position: relative; + top: 0; + + .home-page { + padding: 0 24px; + } + + &-logo { + display: inline-block; + position: relative; + width: 150px; + line-height: 64px; + + & img { + vertical-align: middle; + display: inline-block; + } + + & a { + display: block; + } + } + + &-menu { + float: right; + + .ant-menu { + line-height: 62px; + height: 64px; + + a { + display: block; + } + } + } + + &-item { + &-block { + padding: 0 8px; + + >* { + display: inline-block; + } + } + } + + &-item, + &-item-child, + &-menu { + + .ant-menu-sub .ant-menu-item, + .ant-menu-inline .ant-menu-item { + height: auto; + line-height: 1.5; + } + + .item { + &-sub-item { + display: block; + padding: 8px 24px; + } + + &-image { + float: left; + margin-right: 16px; + margin-top: 4px; + position: relative; + z-index: 1; + } + + &-title { + font-size: 14px; + color: #fff; + margin-left: 46px; + } + + &-content { + font-size: 12px; + color: fade(#fff, 75); + margin-left: 46px; + } + } + } +} + +@media screen and (max-width: 767px) { + .@{header0} { + &-logo { + z-index: 101; + } + + &.home-page-wrapper .home-page { + padding: 0 24px; + } + + &-menu { + height: auto; + float: inherit; + position: relative; + left: -24px; + width: ~"calc(100% + 48px)"; + opacity: 0; + transition: opacity .3s @ease-in-out; + + & li { + padding: 0 24px; + + &.ant-menu-submenu { + padding: 0; + } + } + .item { + &-sub-item { + padding: 8px 0; + } + } + } + + &-mobile-menu { + width: 16px; + height: 14px; + cursor: pointer; + position: absolute; + top: 24px; + right: 24px; + z-index: 100; + + em { + display: block; + width: 100%; + height: 2px; + background: #fff; + margin-top: 4px; + transition: transform .3s @ease-in-out, opacity .3s @ease-in-out; + } + + :first-child { + margin-top: 0; + } + } + + .ant-menu { + height: auto; + overflow: hidden; + + .ant-menu-item-selected { + border: none; + } + } + + & .open { + height: auto; + + .@{header0}-mobile-menu { + em { + &:nth-child(1) { + transform: translateY(6px) rotate(45deg); + } + + &:nth-child(2) { + opacity: 0; + } + + &:nth-child(3) { + transform: translateY(-6px) rotate(-45deg); + } + } + } + + >.@{header0}-menu { + opacity: 1; + pointer-events: auto; + } + } + &-item-block { + height: 40px; + line-height: 40px; + } + } +} diff --git a/client/src/landing/less/pricing1.less b/client/src/landing/less/pricing1.less new file mode 100644 index 000000000..ef736351f --- /dev/null +++ b/client/src/landing/less/pricing1.less @@ -0,0 +1,85 @@ +@pricing1: pricing1; +.@{pricing1}-wrapper { + min-height: 760px; + .@{pricing1} { + >p { + text-align: center; + } + &-content-wrapper { + min-height: 400px; + } + &-block-box { + width: 260px; + border-radius: 4px; + background: #eef0f3; + text-align: center; + color: #666; + min-height: 400px; + margin: auto; + border: 1px solid transparent; + .page-pro(); + &.active { + border-color: @primary-color; + background: #fff; + .@{pricing1} { + &-top-wrapper { + background: @primary-color; + } + &-name, + &-money, + &-button { + color: #fff; + } + &-button { + background: @primary-color; + } + } + } + } + &-block { + margin-bottom: 24px; + } + &-top-wrapper { + width: 100%; + padding: 16px 24px; + } + &-name { + font-size: 14px; + } + &-money { + font-family: 'Helvetica Neue', sans-serif; + font-size: 32px; + color: #666; + } + &-content { + font-size: 12px; + line-height: 2; + font-weight: 300; + margin: 32px 24px 48px; + } + &-line { + display: block; + height: 1px; + background: #d9d9d9; + margin: 0 24px; + } + &-button-wrapper { + margin: 18px 24px; + } + &-button { + padding: 0 24px; + } + } + &.home-page-wrapper { + .@{pricing1}-title-wrapper { + margin-bottom: 64px; + text-align: center; + } + } +} + +@media screen and (max-width: 767px) { + .@{pricing1}-wrapper { + padding-bottom: 0; + } +} diff --git a/client/src/landing/less/pricing2.less b/client/src/landing/less/pricing2.less new file mode 100644 index 000000000..69b193ef7 --- /dev/null +++ b/client/src/landing/less/pricing2.less @@ -0,0 +1,59 @@ +@pricing2: pricing2; + +.@{pricing2}-wrapper { + min-height: 760px; + + .@{pricing2} { + >p { + text-align: center; + } + + &-content-wrapper { + min-height: 400px; + } + + &-table-name-block { + text-align: center; + color: #666; + width: 100%; + } + + &-table-name { + font-size: 24px; + } + + &-table-money { + font-size: 16px; + margin: 8px 0 16px; + } + + &-table-content { + text-align: center; + color: #666; + + &-name { + color: #666; + text-align: center; + } + } + } + + &.home-page-wrapper { + .@{pricing2}-title-wrapper { + margin-bottom: 64px; + text-align: center; + } + } +} + +@media screen and (max-width: 767px) { + .@{pricing2} { + &-wrapper { + padding-bottom: 0; + } + + &-table { + margin-bottom: 24px; + } + } +} diff --git a/client/src/landing/utils.js b/client/src/landing/utils.js new file mode 100644 index 000000000..57cf9cb18 --- /dev/null +++ b/client/src/landing/utils.js @@ -0,0 +1,18 @@ + +import React from 'react'; +import { Button } from 'antd'; + +export const isImg = /^http(s)?:\/\/([\w-]+\.)+[\w-]+(\/[\w-./?%&=]*)?/; +export const getChildrenToRender = (item, i) => { + let tag = item.name.indexOf('title') === 0 ? 'h1' : 'div'; + tag = item.href ? 'a' : tag; + let children = typeof item.children === 'string' && item.children.match(isImg) + ? React.createElement('img', { src: item.children, alt: 'img' }) + : item.children; + if (item.name.indexOf('button') === 0 && typeof item.children === 'object') { + children = React.createElement(Button, { + ...item.children + }); + } + return React.createElement(tag, { key: i.toString(), ...item }, children); +}; diff --git a/client/src/pages/about/about.page.jsx b/client/src/pages/disclaimer/disclaimer.page.jsx similarity index 100% rename from client/src/pages/about/about.page.jsx rename to client/src/pages/disclaimer/disclaimer.page.jsx diff --git a/client/src/pages/landing/landing.page.jsx b/client/src/pages/landing/landing.page.jsx index 03085daf5..9677488e6 100644 --- a/client/src/pages/landing/landing.page.jsx +++ b/client/src/pages/landing/landing.page.jsx @@ -3,6 +3,7 @@ import { connect } from "react-redux"; import { Redirect } from "react-router-dom"; import { createStructuredSelector } from "reselect"; import { selectCurrentUser } from "../../redux/user/user.selectors"; +import LandingPageStatic from "../../landing/index"; const mapStateToProps = createStructuredSelector({ currentUser: selectCurrentUser, @@ -13,5 +14,6 @@ export default connect(mapStateToProps, null)(LandingPage); export function LandingPage({ currentUser }) { if (currentUser.authorized) return ; - return ; + return ; + //return ; } diff --git a/client/src/pages/manage/manage.page.component.jsx b/client/src/pages/manage/manage.page.component.jsx index e66aa2eee..55b51544a 100644 --- a/client/src/pages/manage/manage.page.component.jsx +++ b/client/src/pages/manage/manage.page.component.jsx @@ -15,7 +15,6 @@ import FcmNotification from "../../components/fcm-notification/fcm-notification. //import FooterComponent from "../../components/footer/footer.component"; //Component Imports import HeaderContainer from "../../components/header/header.container"; -import JiraSupportComponent from "../../components/jira-support-widget/jira-support-widget.component"; import LoadingSpinner from "../../components/loading-spinner/loading-spinner.component"; import PartnerPingComponent from "../../components/partner-ping/partner-ping.component"; import PrintCenterModalContainer from "../../components/print-center-modal/print-center-modal.container"; @@ -408,10 +407,9 @@ export function Manage({ match, conflict, bodyshop }) {
- + Disclaimer & Notices - diff --git a/client/src/pages/manage/manage.page.container.jsx b/client/src/pages/manage/manage.page.container.jsx index 047a2d4d3..aecb7f6d5 100644 --- a/client/src/pages/manage/manage.page.container.jsx +++ b/client/src/pages/manage/manage.page.container.jsx @@ -7,6 +7,7 @@ import LoadingSpinner from "../../components/loading-spinner/loading-spinner.com import { QUERY_BODYSHOP } from "../../graphql/bodyshop.queries"; import { setBodyshop } from "../../redux/user/user.actions"; import ManagePage from "./manage.page.component"; +import "../../utils/RegisterSw"; const mapDispatchToProps = (dispatch) => ({ setBodyshop: (bs) => dispatch(setBodyshop(bs)), diff --git a/client/src/pages/tech/tech.page.container.jsx b/client/src/pages/tech/tech.page.container.jsx index 5fb547cd4..4b4647cac 100644 --- a/client/src/pages/tech/tech.page.container.jsx +++ b/client/src/pages/tech/tech.page.container.jsx @@ -9,6 +9,7 @@ import LoadingSpinner from "../../components/loading-spinner/loading-spinner.com import { useTranslation } from "react-i18next"; import { selectBodyshop } from "../../redux/user/user.selectors"; import { createStructuredSelector } from "reselect"; +import "../../utils/RegisterSw"; const mapStateToProps = createStructuredSelector({ bodyshop: selectBodyshop, diff --git a/client/src/redux/application/application.sagas.js b/client/src/redux/application/application.sagas.js index a1c5009ec..3644a5d74 100644 --- a/client/src/redux/application/application.sagas.js +++ b/client/src/redux/application/application.sagas.js @@ -17,7 +17,7 @@ export function* onCalculateScheduleLoad() { } export function* calculateScheduleLoad({ payload: end }) { //REMINDER: Moment.js is not immutable. Today WILL change when adjusted. - const today = moment(new Date()).startOf("day"); + const today = moment().startOf("day"); const state = yield select(); const buckets = state.user.bodyshop.ssbuckets; @@ -42,6 +42,7 @@ export function* calculateScheduleLoad({ payload: end }) { }); prodJobs.forEach((item) => { + //Add all of the jobs currently in production to the buckets so that we have a starting point. const bucketId = CheckJobBucket(buckets, item); if (bucketId) { load.productionTotal[bucketId].count = diff --git a/client/src/translations/en_us/common.json b/client/src/translations/en_us/common.json index 6169f1e75..260e47a2f 100644 --- a/client/src/translations/en_us/common.json +++ b/client/src/translations/en_us/common.json @@ -24,6 +24,7 @@ "cancel": "Cancel", "intake": "Intake", "new": "New Appointment", + "preview": "Preview", "reschedule": "Reschedule", "sendreminder": "Send Reminder", "viewjob": "View Job" @@ -1422,6 +1423,56 @@ "voided": "Job voided successfully." } }, + "landing": { + "bigfeature": { + "subtitle": "ImEX Online is built using world class technology by experts in the collision repair industry. This translates to software that is tailor made for the unique challenges faced by repair facilities with no compromises. ", + "title": "Bringing the latest technology to the automotive repair industry. " + }, + "footer": { + "company": { + "about": "About Us", + "contact": "Contact", + "disclaimers": "Disclaimers", + "name": "Company", + "privacypolicy": "Privacy Policy" + }, + "io": { + "help": "Help", + "name": "ImEX Online", + "status": "System Status" + }, + "slogan": "The future of shop management systems. " + }, + "hero": { + "button": "Learn More", + "title": "Bringing the future to the collision repair process." + }, + "labels": { + "features": "Features", + "managemyshop": "Manage my Shop", + "pricing": "Pricing" + }, + "pricing": { + "basic": { + "name": "Basic", + "sub": "Best suited for shops looking to increase their volume." + }, + "essentials": { + "name": "Essentials", + "sub": "Best suited for small and low volume shops." + }, + "pricingtitle": "Features", + "pro": { + "name": "Pro", + "sub": "Empower your shop with the tools to operate at peak capacity." + }, + "title": "Features", + "unlimited": { + "name": "Unlimited", + "sub": "Everything you need and more for the high volume shop." + } + } + }, "menus": { "currentuser": { "languageselector": "Language", diff --git a/client/src/translations/es/common.json b/client/src/translations/es/common.json index 594f9ac29..485b97639 100644 --- a/client/src/translations/es/common.json +++ b/client/src/translations/es/common.json @@ -24,6 +24,7 @@ "cancel": "Cancelar", "intake": "Consumo", "new": "Nueva cita", + "preview": "", "reschedule": "Reprogramar", "sendreminder": "", "viewjob": "Ver trabajo" @@ -1422,6 +1423,56 @@ "voided": "" } }, + "landing": { + "bigfeature": { + "subtitle": "", + "title": "" + }, + "footer": { + "company": { + "about": "", + "contact": "", + "disclaimers": "", + "name": "", + "privacypolicy": "" + }, + "io": { + "help": "", + "name": "", + "status": "" + }, + "slogan": "" + }, + "hero": { + "button": "", + "title": "" + }, + "labels": { + "features": "", + "managemyshop": "", + "pricing": "" + }, + "pricing": { + "basic": { + "name": "", + "sub": "" + }, + "essentials": { + "name": "", + "sub": "" + }, + "pricingtitle": "", + "pro": { + "name": "", + "sub": "" + }, + "title": "", + "unlimited": { + "name": "", + "sub": "" + } + } + }, "menus": { "currentuser": { "languageselector": "idioma", diff --git a/client/src/translations/fr/common.json b/client/src/translations/fr/common.json index bb27ca4f2..0e596494d 100644 --- a/client/src/translations/fr/common.json +++ b/client/src/translations/fr/common.json @@ -24,6 +24,7 @@ "cancel": "annuler", "intake": "Admission", "new": "Nouveau rendez-vous", + "preview": "", "reschedule": "Replanifier", "sendreminder": "", "viewjob": "Voir le travail" @@ -1422,6 +1423,56 @@ "voided": "" } }, + "landing": { + "bigfeature": { + "subtitle": "", + "title": "" + }, + "footer": { + "company": { + "about": "", + "contact": "", + "disclaimers": "", + "name": "", + "privacypolicy": "" + }, + "io": { + "help": "", + "name": "", + "status": "" + }, + "slogan": "" + }, + "hero": { + "button": "", + "title": "" + }, + "labels": { + "features": "", + "managemyshop": "", + "pricing": "" + }, + "pricing": { + "basic": { + "name": "", + "sub": "" + }, + "essentials": { + "name": "", + "sub": "" + }, + "pricingtitle": "", + "pro": { + "name": "", + "sub": "" + }, + "title": "", + "unlimited": { + "name": "", + "sub": "" + } + } + }, "menus": { "currentuser": { "languageselector": "La langue", diff --git a/client/src/translations/i18n.js b/client/src/translations/i18n.js index 61863eb77..e9cbc3157 100644 --- a/client/src/translations/i18n.js +++ b/client/src/translations/i18n.js @@ -23,7 +23,9 @@ i18n debug: process.env.NODE_ENV === "production" ? false : true, //keySeparator: false, // we do not use keys in form messages.welcome - + react: { + wait: true, + }, interpolation: { escapeValue: false, // react already safes from xss }, diff --git a/client/src/utils/RegisterSw.js b/client/src/utils/RegisterSw.js new file mode 100644 index 000000000..8b2477b8e --- /dev/null +++ b/client/src/utils/RegisterSw.js @@ -0,0 +1,46 @@ +import { AlertOutlined } from "@ant-design/icons"; +import { Button, notification, Space } from "antd"; +import i18n from "i18next"; +import React from "react"; +import * as serviceWorkerRegistration from "../serviceWorkerRegistration"; + +const onServiceWorkerUpdate = (registration) => { + console.log("onServiceWorkerUpdate", registration); + + const btn = ( + + + + + ); + notification.open({ + icon: , + message: i18n.t("general.messages.newversiontitle"), + description: i18n.t("general.messages.newversionmessage"), + duration: 0, + btn, + key: "updateavailable", + }); +}; + +serviceWorkerRegistration.register({ onUpdate: onServiceWorkerUpdate }); diff --git a/client/yarn.lock b/client/yarn.lock index 86d239f03..544b8042a 100644 --- a/client/yarn.lock +++ b/client/yarn.lock @@ -3472,7 +3472,7 @@ babel-preset-react-app@^10.0.0: babel-plugin-macros "2.8.0" babel-plugin-transform-react-remove-prop-types "0.4.24" -babel-runtime@^6.26.0: +babel-runtime@6.x, babel-runtime@^6.26.0: version "6.26.0" resolved "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz" integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4= @@ -4892,6 +4892,13 @@ deep-diff@^0.3.5: resolved "https://registry.npmjs.org/deep-diff/-/deep-diff-0.3.8.tgz" integrity sha1-wB3mPvsO7JeYgB1Ax+Da4ltYLIQ= +deep-eql@~3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" + integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== + dependencies: + type-detect "^4.0.0" + deep-equal@^1.0.1: version "1.1.1" resolved "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz" @@ -5313,6 +5320,18 @@ enhanced-resolve@^4.3.0: memory-fs "^0.5.0" tapable "^1.0.0" +enquire-js@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/enquire-js/-/enquire-js-0.2.1.tgz#f2478cf5808d42f54e8231f20fa133493e7f0fcb" + integrity sha512-4vbcWD0ncK6VQ5M5giOImQb2hFPrKDZH5U+uRX9S6e9vfC6Q5PX6A38PVS6RMnCdr/luDTtJjjLuJinH/+a+Lw== + dependencies: + enquire.js "^2.1.6" + +enquire.js@^2.1.6: + version "2.1.6" + resolved "https://registry.yarnpkg.com/enquire.js/-/enquire.js-2.1.6.tgz#3e8780c9b8b835084c3f60e166dbc3c2a3c89814" + integrity sha1-PoeAybi4NQhMP2DhZtvDwqPImBQ= + enquirer@^2.3.5: version "2.3.6" resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz" @@ -10179,7 +10198,7 @@ prompts@2.4.0, prompts@^2.0.1: kleur "^3.0.3" sisteransi "^1.0.5" -prop-types@15.x, prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.2, prop-types@^15.7.2: +prop-types@15.x, prop-types@^15.0.0, prop-types@^15.5.10, prop-types@^15.5.8, prop-types@^15.6.0, prop-types@^15.6.1, prop-types@^15.6.2, prop-types@^15.7.2: version "15.7.2" resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz" integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ== @@ -10335,7 +10354,7 @@ raf-schd@^4.0.2: resolved "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz" integrity sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ== -raf@^3.4.0, raf@^3.4.1: +raf@3.x, raf@^3.4.0, raf@^3.4.1, raf@~3.4.0: version "3.4.1" resolved "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz" integrity sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA== @@ -10552,6 +10571,16 @@ rc-progress@~3.1.0: "@babel/runtime" "^7.10.1" classnames "^2.2.6" +rc-queue-anim@^1.8.5: + version "1.8.5" + resolved "https://registry.yarnpkg.com/rc-queue-anim/-/rc-queue-anim-1.8.5.tgz#01ef3872bdfa0b70bb915ef9a637fc404244a589" + integrity sha512-vTbZXBu7L3NcXUPjkFN7R80BE+1VYL1QBI10EioYYqZMk6A0iVbjoVAgfoK/Z4gIIxp399gJ8LqbMnQA1AhcXA== + dependencies: + babel-runtime "6.x" + prop-types "^15.6.0" + rc-tween-one "^2.5.0" + react-lifecycles-compat "^3.0.4" + rc-rate@~2.9.0: version "2.9.1" resolved "https://registry.npmjs.org/rc-rate/-/rc-rate-2.9.1.tgz" @@ -10571,6 +10600,18 @@ rc-resize-observer@^1.0.0: rc-util "^5.0.0" resize-observer-polyfill "^1.5.1" +rc-scroll-anim@^2.7.6: + version "2.7.6" + resolved "https://registry.yarnpkg.com/rc-scroll-anim/-/rc-scroll-anim-2.7.6.tgz#f7e6622f2930ca3e1e258f7275bc2e1c26ce791c" + integrity sha512-VwXJYXjZy9TtH1wcQIG7/yjt/Ay3VEjQl/TITaWzK9O7ujjOXRVOYY/tqKshmBMgaJ2oGeFQNmCN8zTwXguq0g== + dependencies: + babel-runtime "6.x" + prop-types "^15.6.0" + raf "3.x" + rc-tween-one "^2.4.0" + react-lifecycles-compat "^3.0.4" + tween-functions "1.x" + rc-select@^12.0.0, rc-select@~12.1.6: version "12.1.10" resolved "https://registry.npmjs.org/rc-select/-/rc-select-12.1.10.tgz" @@ -10687,6 +10728,30 @@ rc-trigger@^5.0.0, rc-trigger@^5.0.4, rc-trigger@^5.1.2, rc-trigger@^5.2.1: rc-motion "^2.0.0" rc-util "^5.5.0" +rc-tween-one@^1.2.5: + version "1.8.1" + resolved "https://registry.yarnpkg.com/rc-tween-one/-/rc-tween-one-1.8.1.tgz#5b3b464b9bf2c369efc16c816cccf57bc16ae253" + integrity sha512-Avg8EXHdt6ABV9WnmTmh6zEaAzUvl4bFZKbP3y6BE8UGBGp1qUhlIgCB83gL+5eA0VECdM/b9PsEBRrcxzSpGw== + dependencies: + babel-runtime "6.x" + deep-eql "~3.0.1" + prop-types "^15.6.1" + raf "~3.4.0" + style-utils "~0.1.13" + tween-functions "~1.2.0" + +rc-tween-one@^2.4.0, rc-tween-one@^2.5.0: + version "2.7.3" + resolved "https://registry.yarnpkg.com/rc-tween-one/-/rc-tween-one-2.7.3.tgz#c9d3c44743e25c654d65c22ec3934afd79923fae" + integrity sha512-n4OPRLO6VMZHj61unq5KKxHMMfBz52bxob94fN3U5M9GqFg3H+T3TXnpHPnAK+cq/xBGo70ik2vB4Fpjo/txcA== + dependencies: + babel-runtime "6.x" + prop-types "^15.6.1" + raf "~3.4.0" + react-lifecycles-compat "^3.0.4" + style-utils "~0.2.0" + tween-functions "~1.2.0" + rc-upload@~4.3.0: version "4.3.1" resolved "https://registry.npmjs.org/rc-upload/-/rc-upload-4.3.1.tgz" @@ -11064,6 +11129,14 @@ react-smooth@^2.0.0: raf "^3.4.0" react-transition-group "2.9.0" +react-sublime-video@^0.2.5: + version "0.2.5" + resolved "https://registry.yarnpkg.com/react-sublime-video/-/react-sublime-video-0.2.5.tgz#c967b8e9a374b36d6a5d1b63b93fa6ec02e54842" + integrity sha1-yWe46aN0s21qXRtjuT+m7ALlSEI= + dependencies: + prop-types "^15.5.10" + rc-tween-one "^1.2.5" + react-transition-group@2, react-transition-group@2.9.0: version "2.9.0" resolved "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz" @@ -12441,6 +12514,16 @@ style-loader@1.3.0: loader-utils "^2.0.0" schema-utils "^2.7.0" +style-utils@~0.1.13: + version "0.1.24" + resolved "https://registry.yarnpkg.com/style-utils/-/style-utils-0.1.24.tgz#fc0675d79a0b201bf86fc5d5a1dd202f838de544" + integrity sha512-MVZSKubpU/vIfpmOsi8/0ckWxb0WmGBmyNoEDGWZM9cM8n8sCL6DJftl3lEf8Uy5zKQ9+O1XdJxscWTDosCQpQ== + +style-utils@~0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/style-utils/-/style-utils-0.2.1.tgz#c78fe6696214f4ab12701959f09553e9d81dd45b" + integrity sha512-eKRIfWnUSdBqe2ko+qisUwBSlfWpHru89geRqzmScpDhkPW1ksmE04d//nDcXeF+TVK5cnBG90mMmHgxyxXleQ== + styled-components@^5.3.0: version "5.3.0" resolved "https://registry.npmjs.org/styled-components/-/styled-components-5.3.0.tgz" @@ -12848,6 +12931,11 @@ tty-browserify@0.0.0: resolved "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz" integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= +tween-functions@1.x, tween-functions@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/tween-functions/-/tween-functions-1.2.0.tgz#1ae3a50e7c60bb3def774eac707acbca73bbc3ff" + integrity sha1-GuOlDnxguz3vd06scHrLynO7w/8= + type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" @@ -12862,7 +12950,7 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -type-detect@4.0.8: +type-detect@4.0.8, type-detect@^4.0.0: version "4.0.8" resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==