Skip to content

Commit 74d616f

Browse files
committed
upload
1 parent 226643d commit 74d616f

8 files changed

Lines changed: 356 additions & 0 deletions

File tree

src/admin/client/lib/api.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import CezerinClient from 'cezerin-client';
2+
import settings from 'lib/settings';
3+
4+
let api = null;
5+
let dashboardToken = localStorage.getItem('dashboard_token');
6+
let webstoreToken = localStorage.getItem('webstore_token');
7+
8+
const DEVELOPER_MODE = settings.developerMode === true;
9+
10+
if (dashboardToken || DEVELOPER_MODE === true) {
11+
api = new CezerinClient({
12+
apiBaseUrl: settings.apiBaseUrl || '/api/v1',
13+
apiToken: dashboardToken,
14+
webstoreToken: webstoreToken
15+
});
16+
}
17+
18+
export default api;
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import messages from 'lib/text';
2+
import settings from 'lib/settings';
3+
import { installReceive } from 'modules/settings/actions';
4+
import { fetchOrders } from 'modules/orders/actions';
5+
6+
const AUTO_RECONNECT_INTERVAL = 1000; //1 seconds
7+
const ORDER_CREATED = 'order.created';
8+
const THEME_INSTALLED = 'theme.installed';
9+
let store = null;
10+
11+
export const connectToWebSocket = reduxStore => {
12+
store = reduxStore;
13+
connect();
14+
};
15+
16+
const connect = () => {
17+
const wsUrl =
18+
settings.apiWebSocketUrl && settings.apiWebSocketUrl.length > 0
19+
? settings.apiWebSocketUrl
20+
: getWebSocketUrlFromCurrentLocation();
21+
22+
const token = localStorage.getItem('dashboard_token');
23+
const ws = new WebSocket(`${wsUrl}/ws/dashboard?token=${token}`);
24+
25+
ws.onmessage = onMessage;
26+
ws.onopen = onOpen;
27+
ws.onclose = onClose;
28+
ws.onerror = onError;
29+
};
30+
31+
const getWebSocketUrlFromCurrentLocation = () => {
32+
const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
33+
return `${wsProtocol}//${window.location.host}`;
34+
};
35+
36+
const onMessage = event => {
37+
try {
38+
const message = JSON.parse(event.data);
39+
eventHandler(message);
40+
} catch (err) {}
41+
};
42+
43+
const onOpen = () => {
44+
if (settings.developerMode === true) {
45+
console.log('Connection established.');
46+
}
47+
};
48+
49+
const onError = () => {};
50+
51+
const onClose = event => {
52+
if (event.code !== 1000) {
53+
if (settings.developerMode === true) {
54+
console.log(`WebSocket connection closed with code: ${event.code}.`);
55+
}
56+
// try to reconnect
57+
setTimeout(() => {
58+
connect();
59+
}, AUTO_RECONNECT_INTERVAL);
60+
}
61+
};
62+
63+
const showNotification = (title, body, requireInteraction = false) => {
64+
let msg = new Notification(title, {
65+
body: body,
66+
tag: 'dashboard',
67+
requireInteraction: requireInteraction
68+
});
69+
70+
msg.addEventListener('click', event => {
71+
parent.focus();
72+
event.target.close();
73+
});
74+
};
75+
76+
const eventHandler = ({ event, payload }) => {
77+
switch (event) {
78+
case THEME_INSTALLED:
79+
const fileName = payload;
80+
store.dispatch(installReceive());
81+
showNotification(messages.settings_theme, messages.themeInstalled);
82+
break;
83+
case ORDER_CREATED:
84+
const order = payload;
85+
store.dispatch(fetchOrders());
86+
showNotification(
87+
`${messages.order} #${order.number}`,
88+
`${order.shipping_address.full_name}, ${order.shipping_address.city}`,
89+
true
90+
);
91+
break;
92+
default:
93+
break;
94+
}
95+
};

src/admin/client/lib/auth.js

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
import settings from './settings';
2+
import api from './api';
3+
import messages from './text';
4+
5+
const LOGIN_PATH = '/admin/login';
6+
const HOME_PATH = '/admin/';
7+
8+
const getParameterByName = (name, url) => {
9+
if (!url) url = window.location.href;
10+
name = name.replace(/[\[\]]/g, '\\$&');
11+
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
12+
results = regex.exec(url);
13+
if (!results) return null;
14+
if (!results[2]) return '';
15+
return decodeURIComponent(results[2].replace(/\+/g, ' '));
16+
};
17+
18+
export const validateCurrentToken = () => {
19+
if (location.pathname !== LOGIN_PATH) {
20+
if (!isCurrentTokenValid()) {
21+
location.replace(LOGIN_PATH);
22+
}
23+
}
24+
};
25+
26+
export const checkTokenFromUrl = () => {
27+
if (location.pathname === LOGIN_PATH) {
28+
const token = getParameterByName('token');
29+
if (token && token !== '') {
30+
const tokenData = parseJWT(token);
31+
32+
if (tokenData) {
33+
const expiration_date = tokenData.exp * 1000;
34+
if (expiration_date > Date.now()) {
35+
saveToken({ token, email: tokenData.email, expiration_date });
36+
location.replace(HOME_PATH);
37+
} else {
38+
alert(messages.tokenExpired);
39+
}
40+
} else {
41+
alert(messages.tokenInvalid);
42+
}
43+
} else {
44+
if (isCurrentTokenValid()) {
45+
location.replace(HOME_PATH);
46+
}
47+
}
48+
}
49+
};
50+
51+
const parseJWT = jwt => {
52+
try {
53+
const payload = jwt.split('.')[1];
54+
const tokenData = JSON.parse(atob(payload));
55+
return tokenData;
56+
} catch (e) {
57+
return null;
58+
}
59+
};
60+
61+
const saveToken = data => {
62+
localStorage.setItem('dashboard_token', data.token);
63+
localStorage.setItem('dashboard_email', data.email);
64+
localStorage.setItem('dashboard_exp', data.expiration_date);
65+
};
66+
67+
const isCurrentTokenValid = () => {
68+
const expiration_date = localStorage.getItem('dashboard_exp');
69+
return (
70+
localStorage.getItem('dashboard_token') &&
71+
expiration_date &&
72+
expiration_date > Date.now()
73+
);
74+
};
75+
76+
export const removeToken = () => {
77+
localStorage.removeItem('dashboard_token');
78+
localStorage.removeItem('dashboard_email');
79+
localStorage.removeItem('dashboard_exp');
80+
localStorage.removeItem('webstore_token');
81+
localStorage.removeItem('webstore_email');
82+
localStorage.removeItem('webstore_exp');
83+
location.replace(LOGIN_PATH);
84+
};

src/admin/client/lib/data.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export default {
2+
countries: APPLICATION_DATA_COUNTRIES,
3+
currencies: APPLICATION_DATA_CURRENCIES,
4+
timezones: APPLICATION_DATA_TIMEZONES
5+
};

src/admin/client/lib/helper.js

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import messages from './text';
2+
3+
export const formatNumber = (number, settings) => {
4+
const x = 3;
5+
const floatNumber = parseFloat(number || 0) || 0;
6+
7+
const re =
8+
'\\d(?=(\\d{' +
9+
x +
10+
'})+' +
11+
(settings.decimal_number > 0 ? '\\D' : '$') +
12+
')';
13+
14+
let num = floatNumber.toFixed(Math.max(0, ~~settings.decimal_number));
15+
16+
return (settings.decimal_separator
17+
? num.replace('.', settings.decimal_separator)
18+
: num
19+
).replace(new RegExp(re, 'g'), '$&' + settings.thousand_separator);
20+
};
21+
22+
const amountPattern = '{amount}';
23+
export const formatCurrency = (number = 0, settings) => {
24+
return settings.currency_format.replace(
25+
amountPattern,
26+
formatNumber(number, settings)
27+
);
28+
};
29+
30+
export const formatFileSize = (bytes = 0) => {
31+
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
32+
if (bytes === 0) {
33+
return 'n/a';
34+
} else {
35+
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10);
36+
if (i === 0) {
37+
return `${bytes} ${sizes[i]}`;
38+
} else {
39+
return `${(bytes / 1024 ** i).toFixed(1)} ${sizes[i]}`;
40+
}
41+
}
42+
};
43+
44+
export const getThumbnailUrl = (originalUrl, width) => {
45+
if (originalUrl && originalUrl.length > 0) {
46+
const pos = originalUrl.lastIndexOf('/');
47+
const thumbnailUrl =
48+
originalUrl.substring(0, pos) +
49+
`/${width}/` +
50+
originalUrl.substring(pos + 1);
51+
return thumbnailUrl;
52+
} else {
53+
return '';
54+
}
55+
};
56+
57+
export const getOrderFieldLabelByKey = key => {
58+
switch (key) {
59+
case 'full_name':
60+
return messages.fullName;
61+
case 'address1':
62+
return messages.address1;
63+
case 'address2':
64+
return messages.address2;
65+
case 'postal_code':
66+
return messages.postal_code;
67+
case 'phone':
68+
return messages.phone;
69+
case 'company':
70+
return messages.company;
71+
case 'mobile':
72+
return messages.mobile;
73+
case 'city':
74+
return messages.city;
75+
case 'comments':
76+
return messages.customerComment;
77+
default:
78+
return '';
79+
}
80+
};

src/admin/client/lib/settings.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default APPLICATION_CONFIG;

src/admin/client/lib/text.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export default APPLICATION_TEXT;
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import messages from './text';
2+
3+
const LOGIN_PATH = '/admin/apps/login';
4+
const HOME_PATH = '/admin/apps';
5+
6+
const getParameterByName = (name, url) => {
7+
if (!url) url = window.location.href;
8+
name = name.replace(/[\[\]]/g, '\\$&');
9+
var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
10+
results = regex.exec(url);
11+
if (!results) return null;
12+
if (!results[2]) return '';
13+
return decodeURIComponent(results[2].replace(/\+/g, ' '));
14+
};
15+
16+
export const validateCurrentToken = () => {
17+
if (location.pathname !== LOGIN_PATH) {
18+
if (!isCurrentTokenValid()) {
19+
location.replace(LOGIN_PATH);
20+
}
21+
}
22+
};
23+
24+
export const checkTokenFromUrl = () => {
25+
if (location.pathname === LOGIN_PATH) {
26+
const token = getParameterByName('webstoretoken');
27+
if (token && token !== '') {
28+
const tokenData = parseJWT(token);
29+
30+
if (tokenData) {
31+
const expiration_date = tokenData.exp * 1000;
32+
if (expiration_date > Date.now()) {
33+
saveToken({ token, email: tokenData.email, expiration_date });
34+
location.replace(HOME_PATH);
35+
} else {
36+
alert(messages.tokenExpired);
37+
}
38+
} else {
39+
alert(messages.tokenInvalid);
40+
}
41+
} else {
42+
if (isCurrentTokenValid()) {
43+
location.replace(HOME_PATH);
44+
}
45+
}
46+
}
47+
};
48+
49+
const parseJWT = jwt => {
50+
try {
51+
const payload = jwt.split('.')[1];
52+
const tokenData = JSON.parse(atob(payload));
53+
return tokenData;
54+
} catch (e) {
55+
return null;
56+
}
57+
};
58+
59+
const saveToken = data => {
60+
localStorage.setItem('webstore_token', data.token);
61+
localStorage.setItem('webstore_email', data.email);
62+
localStorage.setItem('webstore_exp', data.expiration_date);
63+
};
64+
65+
export const isCurrentTokenValid = () => {
66+
const expiration_date = localStorage.getItem('webstore_exp');
67+
return (
68+
localStorage.getItem('webstore_token') &&
69+
expiration_date &&
70+
expiration_date > Date.now()
71+
);
72+
};

0 commit comments

Comments
 (0)