@autobusal/providers 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,56 @@
1
+ import { Toaster } from 'react-hot-toast';
2
+ import useSystemTheme from '../Styles/hooks/useSystemTheme';
3
+ import { GetSettings } from '../services';
4
+
5
+ interface Props {
6
+ children: JSX.Element
7
+ }
8
+
9
+ export const Provider = ({ children }: Props): JSX.Element => {
10
+ const { data } = GetSettings();
11
+
12
+ const mode = useSystemTheme();
13
+
14
+ const ourTheme: any = data.colors[mode as keyof typeof data.colors];
15
+
16
+ return (
17
+ <>
18
+ { children }
19
+
20
+ <Toaster
21
+ position="top-right"
22
+ gutter={ 12 }
23
+ toastOptions={{
24
+ style: {
25
+ padding: '6px 10px',
26
+ fontSize: data.theme.size.xs,
27
+ color: ourTheme.font.normal,
28
+ fontWeight: '700',
29
+ background: ourTheme.background.normal,
30
+ borderRadius: ourTheme.borderRadius,
31
+ boxShadow: ourTheme.boxShadow
32
+ },
33
+
34
+ success: {
35
+ style: {
36
+ background: ourTheme.font.success,
37
+ color: '#FFFFFF'
38
+ }
39
+ },
40
+
41
+ error: {
42
+ style: {
43
+ background: ourTheme.font.error,
44
+ color: '#FFFFFF'
45
+ }
46
+ }
47
+ }}
48
+ containerStyle={{
49
+ top: '70px'
50
+ }}
51
+ />
52
+ </>
53
+ );
54
+ };
55
+
56
+ export default Provider;
package/Providers.tsx CHANGED
@@ -1,45 +1,27 @@
1
- // import { Provider as ProviderStyles } from './Styles/Provider';
2
- // import { Provider as ProviderQueries } from './Queries/Provider';
3
- // import { Provider as ProviderNotifications } from './Notifications/Provider';
4
- // import loadLanguages from './Languages/loadLanguages';
5
- // import loadAnalytics from './Analytics/loadAnalytics';
6
-
7
- // import { Suspense } from 'react';
8
- // import { ProviderStyles, ProviderQueries, ProviderNotifications, loadLanguages, loadAnalytics } from './providers';
9
- // import { General } from '@components/Loading/Loading';
10
-
11
- // ProviderStyles,
12
- // ProviderQueries,
13
- // ProviderNotifications,
14
- // loadLanguages,
15
- // loadAnalytics
16
-
17
- // // load the languages
18
- // loadLanguages();
19
-
20
- // // load analytics
21
- // loadAnalytics();
22
-
23
- // const App = (): JSX.Element => (
24
- // <ProviderStyles>
25
- // <ProviderQueries>
26
- // <ProviderNotifications>
27
- // <Suspense fallback={ <General /> }>
28
- // <Routing />
29
- // </Suspense>
30
- // </ProviderNotifications>
31
- // </ProviderQueries>
32
- // </ProviderStyles>
33
- // );
1
+ import { Suspense } from 'react';
2
+ import Queries from './Queries/Queries';
3
+ import Styles from './Styles/Styles';
4
+ import Notifications from './Notifications/Notifications';
5
+ import Setup from './Setup/Setup';
34
6
 
35
7
  interface Props {
8
+ type: 'normal' | 'whitelabel'
9
+ loading: JSX.Element
36
10
  children: JSX.Element
37
11
  }
38
12
 
39
- const Providers = ({ children }: Props): JSX.Element => (
40
- <div>
41
- Hello World!
42
- </div>
13
+ const Providers = ({ type, loading, children }: Props): JSX.Element => (
14
+ <Queries>
15
+ <Styles>
16
+ <Notifications>
17
+ <Setup type={ type }>
18
+ <Suspense fallback={ loading }>
19
+ { children }
20
+ </Suspense>
21
+ </Setup>
22
+ </Notifications>
23
+ </Styles>
24
+ </Queries>
43
25
  );
44
26
 
45
27
  export default Providers;
@@ -0,0 +1,22 @@
1
+ import { QueryClientProvider, QueryClient } from '@tanstack/react-query';
2
+
3
+ const queryClient = new QueryClient({
4
+ defaultOptions: {
5
+ queries: {
6
+ refetchOnWindowFocus: false,
7
+ retry: false
8
+ }
9
+ }
10
+ });
11
+
12
+ interface Props {
13
+ children: JSX.Element
14
+ }
15
+
16
+ const Queries = ({ children }: Props): JSX.Element => (
17
+ <QueryClientProvider client={ queryClient }>
18
+ { children }
19
+ </QueryClientProvider>
20
+ );
21
+
22
+ export default Queries;
@@ -0,0 +1,49 @@
1
+ import axios from 'axios';
2
+ // import i18next from 'i18next';
3
+ // import { error } from '@utilities/notify';
4
+
5
+ const apiClient = axios.create({
6
+ baseURL: import.meta.env.VITE_API_OBT,
7
+ withCredentials: true
8
+ });
9
+
10
+ apiClient.interceptors.request.use(
11
+ config => {
12
+ // // const token = localStorage.getItem('token');
13
+
14
+ // // if (token !== null) {
15
+ // // config.headers.Authorization = token;
16
+ // // }
17
+
18
+ return config;
19
+ }
20
+ );
21
+
22
+ apiClient.interceptors.response.use(response => (
23
+ response
24
+ ), err => {
25
+ console.log(err.response);
26
+
27
+ // if (err.response) {
28
+ // // if we have a 401, we go to the logout page
29
+ // // if (err.response.status === 401) {
30
+ // // alert(401);
31
+ // // }
32
+
33
+ // // @todo: how to handle 404?
34
+
35
+ // // if we have a 422 error, we display the message
36
+ // if (err.response.status === 422) {
37
+ // error(err.response.data.message);
38
+ // }
39
+ // } else if (err.request) {
40
+ // // if we have a 500 error, we display an error message
41
+ // error(i18next.t('server_error', { ns: 'general' }))
42
+ // } else {
43
+ // console.log('ERROR', err.message);
44
+ // }
45
+
46
+ return err;
47
+ });
48
+
49
+ export default apiClient;
@@ -0,0 +1,39 @@
1
+ import { Helmet } from 'react-helmet';
2
+ import { SettingsData } from '../types';
3
+
4
+ interface Props {
5
+ data: SettingsData
6
+ children: JSX.Element
7
+ }
8
+
9
+ // @todo: De adaugat din tema Favicons
10
+ const Preload = ({ data, children }: Props): JSX.Element => {
11
+ // we arrange the font family names before inserting them
12
+ const fontTitle = data.theme.fontFamily.title.replace(/\ /g, '+');
13
+ const fontContent = data.theme.fontFamily.content.replace(/\ /g, '+');
14
+
15
+ return (
16
+ <>
17
+ <Helmet>
18
+ <title>{ data.preferences.company }</title>
19
+
20
+ {/* <!-- Favicons --> */}
21
+ {/* <link rel="apple-touch-icon" sizes="180x180" href="/favicons/apple-touch-icon.png" /> */}
22
+ {/* <link rel="icon" type="image/png" sizes="32x32" href="/favicons/favicon-32x32.png" /> */}
23
+ {/* <link rel="icon" type="image/png" sizes="16x16" href="/favicons/favicon-16x16.png" /> */}
24
+ {/* <link rel="manifest" href="/favicons/site.webmanifest" /> */}
25
+ {/* <link rel="mask-icon" href="/favicons/safari-pinned-tab.svg" color="#5bbad5" /> */}
26
+ {/* <link rel="shortcut icon" href="/favicons/favicon.ico" /> */}
27
+ {/* <meta name="msapplication-TileColor" content="#ffffff" /> */}
28
+ {/* <meta name="msapplication-config" content="/favicons/browserconfig.xml" /> */}
29
+ {/* <meta name="theme-color" content="#ffffff" /> */}
30
+
31
+ <link href={ `https://fonts.googleapis.com/css2?family=${ fontTitle }:wght@700&family=${ fontContent }:wght@300;400;700&display=swap` } rel="stylesheet" />
32
+ </Helmet>
33
+
34
+ { children }
35
+ </>
36
+ );
37
+ };
38
+
39
+ export default Preload;
@@ -0,0 +1,27 @@
1
+ import Preload from './Preload';
2
+ import languages from './utilities/languages';
3
+ import analytics from './utilities/analytics';
4
+ import { GetSettings, GetMenu } from '../services';
5
+
6
+ interface Props {
7
+ type: 'normal' | 'whitelabel'
8
+ children: JSX.Element
9
+ }
10
+
11
+ const Setup = ({ type, children }: Props): JSX.Element => {
12
+ const { data } = GetSettings();
13
+
14
+ GetMenu();
15
+
16
+ languages(type, data.preferences.languages.default);
17
+
18
+ analytics(data.preferences.googleAnalyticsID);
19
+
20
+ return (
21
+ <Preload data={ data }>
22
+ { children }
23
+ </Preload>
24
+ );
25
+ };
26
+
27
+ export default Setup;
@@ -0,0 +1,9 @@
1
+ import ReactGA from 'react-ga4';
2
+
3
+ const analytics = (id: string | null): void => {
4
+ if (id !== null) {
5
+ ReactGA.initialize(id);
6
+ }
7
+ };
8
+
9
+ export default analytics;
@@ -0,0 +1,25 @@
1
+ import i18next from 'i18next';
2
+ import Backend from 'i18next-http-backend';
3
+ import { initReactI18next } from 'react-i18next';
4
+
5
+ const languages = (type: string, defaultLanguage: string): void => {
6
+ const currentLanguage = localStorage.getItem('language');
7
+
8
+ i18next
9
+ .use(Backend)
10
+ .use(initReactI18next)
11
+ .init({
12
+ interpolation: {
13
+ escapeValue: false
14
+ },
15
+ lng: currentLanguage ?? defaultLanguage,
16
+ fallbackLng: defaultLanguage,
17
+ debug: true,
18
+ backend: {
19
+ loadPath: `${ import.meta.env.VITE_API_OBT }/languages/${ type }/{{lng}}/{{ns}}.json`
20
+ },
21
+ ns: 'general'
22
+ });
23
+ };
24
+
25
+ export default languages;
@@ -0,0 +1,112 @@
1
+ import { createGlobalStyle } from 'styled-components';
2
+
3
+ const GlobalStyles = createGlobalStyle`
4
+ * {
5
+ outline: none;
6
+ box-sizing: border-box;
7
+ }
8
+
9
+ html {
10
+ height: 100%;
11
+ font-family: sans-serif;
12
+ -webkit-text-size-adjust: 100%;
13
+ -ms-text-size-adjust: 100%;
14
+ -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
15
+ }
16
+
17
+ body {
18
+ height: 100%;
19
+ margin: 0;
20
+ padding: 0;
21
+ font-family: '${props => props.theme.fontFamily.content}', sans-serif;
22
+ color: ${ props => props.theme.font.normal };
23
+ font-size: ${ props => props.theme.size.m };
24
+ line-height: ${ props => props.theme.lineHeight.content };
25
+ background: ${ props => props.theme.background.normal };
26
+ }
27
+
28
+ #root {
29
+ width: 100%;
30
+ height: 100%;
31
+ }
32
+
33
+ a {
34
+ color: ${ props => props.theme.font.normal };
35
+ text-decoration: none;
36
+
37
+ &:hover {
38
+ text-decoration: underline;
39
+ }
40
+ }
41
+
42
+ button {
43
+ all: unset;
44
+ box-sizing: border-box;
45
+ cursor: pointer;
46
+ }
47
+
48
+ h1, h2, h3, h4, h5, h6 {
49
+ display: block;
50
+ margin: 0 0 20px 0;
51
+ padding: 0;
52
+ font-weight: 700;
53
+ line-height: ${ props => props.theme.lineHeight.title };
54
+ font-family: ${ props => props.theme.fontFamily.title };
55
+ }
56
+
57
+ h1 {
58
+ font-size: ${ props => props.theme.size.xxl };
59
+ }
60
+ h2, h3 {
61
+ font-size: ${ props => props.theme.size.xl };
62
+ }
63
+ h4, h5, h6 {
64
+ font-size: ${ props => props.theme.size.l };
65
+ }
66
+
67
+ input[type='text'], input[type='number'], input[type='email'], input[type='password'], textarea, select {
68
+ display: block;
69
+ width: 100%;
70
+ height: 38px;
71
+ padding: 0 10px;
72
+ font-size: ${ props => props.theme.size.m };
73
+ font-weight: 700;
74
+ color: ${ props => props.theme.font.normal };
75
+ background: ${ props => props.theme.background.normal };
76
+ border: 1px solid ${ props => props.theme.font.faded };
77
+ border-radius: ${ props => props.theme.borderRadius };
78
+ -webkit-appearance: none;
79
+ }
80
+
81
+ input[type='checkbox'] {
82
+ -webkit-appearance: checkbox;
83
+ }
84
+
85
+ input[type='radio'] {
86
+ display: inline-block;
87
+ margin-right: 5px;
88
+ -webkit-appearance: radio;
89
+ }
90
+
91
+ select {
92
+ padding: 0 10px;
93
+ font-size: ${ props => props.theme.size.m };
94
+ }
95
+
96
+ textarea {
97
+ min-height: 120px;
98
+ resize: vertical;
99
+ padding: 10px;
100
+ font-family: '${props => props.theme.fontFamily.content}', sans-serif;
101
+ font-size: ${ props => props.theme.size.s };
102
+ line-height: ${ props => props.theme.lineHeight.title };
103
+ font-weight: 700;
104
+ }
105
+
106
+ p {
107
+ padding: 0;
108
+ margin: 0;
109
+ }
110
+ `;
111
+
112
+ export default GlobalStyles;
@@ -0,0 +1,24 @@
1
+ import { ThemeProvider } from 'styled-components';
2
+ import useSystemTheme from './hooks/useSystemTheme';
3
+ import GlobalStyles from './GlobalStyles';
4
+ import { GetSettings } from '../services';
5
+
6
+ interface Props {
7
+ children: JSX.Element
8
+ }
9
+
10
+ const Styles = ({ children }: Props): JSX.Element => {
11
+ const { data } = GetSettings();
12
+
13
+ const mode = useSystemTheme();
14
+
15
+ return (
16
+ <ThemeProvider theme={ { ...data.colors[mode as keyof typeof data.colors], ...data.theme } }>
17
+ <GlobalStyles />
18
+
19
+ { children }
20
+ </ThemeProvider>
21
+ );
22
+ };
23
+
24
+ export default Styles;
@@ -0,0 +1,18 @@
1
+ import { useState, useEffect } from 'react';
2
+
3
+ const useSystemTheme = (): string => {
4
+ const queryDarkMode = window.matchMedia("(prefers-color-scheme: dark)");
5
+
6
+ const [ theme, setTheme ] = useState<string>(queryDarkMode.matches ? 'dark' : 'light');
7
+
8
+ // setup a listener to respond to future changes of the system theme
9
+ useEffect(() => {
10
+ queryDarkMode.addEventListener('change', (event: MediaQueryListEvent) => {
11
+ setTheme(event.matches ? 'dark' : 'light');
12
+ })
13
+ });
14
+
15
+ return theme;
16
+ };
17
+
18
+ export default useSystemTheme;
package/index.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  import Providers from './Providers';
2
+ import apiClient from './Queries/apiClient';
2
3
 
3
- // export {
4
-
5
- // };
4
+ export {
5
+ apiClient
6
+ };
6
7
 
7
8
  export default Providers;
package/package.json CHANGED
@@ -1,5 +1,17 @@
1
1
  {
2
2
  "name": "@autobusal/providers",
3
- "version": "1.0.1",
4
- "type": "module"
3
+ "version": "1.0.3",
4
+ "type": "module",
5
+ "main": "index.ts",
6
+ "dependencies": {
7
+ "@tanstack/react-query": "^5.17.19",
8
+ "axios": "^1.6.5",
9
+ "i18next": "^23.7.18",
10
+ "i18next-http-backend": "^2.4.2",
11
+ "react-ga4": "^2.1.0",
12
+ "react-helmet": "^6.1.0",
13
+ "react-hot-toast": "^2.4.1",
14
+ "react-i18next": "^14.0.1",
15
+ "styled-components": "^6.1.8"
16
+ }
5
17
  }
package/services.ts ADDED
@@ -0,0 +1,32 @@
1
+ import { useSuspenseQuery, UseSuspenseQueryResult } from '@tanstack/react-query';
2
+ import apiClient from './Queries/apiClient';
3
+ import { SettingsData, MenuData } from './types';
4
+
5
+ export const GetSettings = (): UseSuspenseQueryResult<SettingsData> => (
6
+ useSuspenseQuery({
7
+ queryKey: ['get-settings'],
8
+ queryFn: async () => (
9
+ await apiClient
10
+ .get('/api/settings/get')
11
+ .then(response => (
12
+ response.data
13
+ ))
14
+ .catch(() => {})
15
+ ),
16
+ staleTime: Infinity
17
+ })
18
+ );
19
+
20
+ export const GetMenu = (): UseSuspenseQueryResult<MenuData> => (
21
+ useSuspenseQuery({
22
+ queryKey: ['get-menu'],
23
+ queryFn: async () => (
24
+ await apiClient
25
+ .get('/api/menu/get')
26
+ .then(response => (
27
+ response.data
28
+ ))
29
+ .catch(() => {})
30
+ )
31
+ })
32
+ );
package/types.ts ADDED
@@ -0,0 +1,33 @@
1
+ export interface SettingsData {
2
+ preferences: {
3
+ company: string
4
+ logo: string
5
+
6
+ googleAnalyticsID: string | null
7
+
8
+ languages: {
9
+ available: string[]
10
+ default: string
11
+ }
12
+ }
13
+
14
+ theme: {
15
+ fontFamily: any
16
+ lineHeight: any
17
+ size: any
18
+ borderRadius: string
19
+ }
20
+
21
+ colors: {
22
+ light: any
23
+ dark: any
24
+ }
25
+ }
26
+
27
+ export interface MenuData {
28
+ id: number
29
+ name: string
30
+ link: string
31
+ new: 'yes' | 'no'
32
+ children: MenuData[]
33
+ }