@controleonline/ui-common 1.2.70 → 1.2.75
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.
- package/.github/actions/workers/manager/action.yml +147 -0
- package/.github/actions/workers/qa/action.yml +44 -0
- package/.github/actions/workers/security/action.yml +44 -0
- package/.github/actions/workers/technical-documenter/action.yml +51 -0
- package/.github/workflows/manager-worker.yml +168 -0
- package/.github/workflows/publish-npm.yml +45 -0
- package/.gitmodules +3 -0
- package/AGENTS.md +6 -0
- package/README.md +14 -0
- package/package.json +32 -28
- package/src/api/fetch.js +1 -1
- package/src/api/index.js +328 -58
- package/src/react/components/AddImportModal.js +95 -111
- package/src/react/components/AnimatedModal.js +171 -0
- package/src/react/components/AnimatedModal.styles.js +21 -0
- package/src/react/components/AppTypeSwitcher.js +164 -0
- package/src/react/components/AppTypeSwitcher.styles.js +109 -0
- package/src/react/components/BackgroundRuntimeBridge.js +5 -4
- package/src/react/components/BottomNavigationBar.config.js +211 -231
- package/src/react/components/BottomNavigationBar.js +86 -31
- package/src/react/components/BottomNavigationBar.styles.js +118 -110
- package/src/react/components/CategoryForm.js +52 -35
- package/src/react/components/DefaultProvider.native.js +194 -156
- package/src/react/components/DefaultProvider.web.js +188 -112
- package/src/react/components/DeliveryPushBridge.native.js +2 -2
- package/src/react/components/DeviceAlertSoundService.js +3 -3
- package/src/react/components/KioskModeBridge.js +2 -2
- package/src/react/components/LauncherModeBridge.js +2 -2
- package/src/react/components/ManagerPushBridge.native.js +2 -2
- package/src/react/components/NetworkPrinterPreviewModal.js +249 -0
- package/src/react/components/NetworkPrinterPreviewModal.styles.js +159 -0
- package/src/react/components/RemoteCheckoutService.js +28 -20
- package/src/react/components/RuntimeBottomNavigationBar.js +146 -119
- package/src/react/components/RuntimeInfoFooter.js +137 -45
- package/src/react/components/RuntimeInfoFooter.styles.js +3 -0
- package/src/react/components/StateStore.js +258 -0
- package/src/react/components/UnifiedPaymentBar.js +7 -4
- package/src/react/components/UserAvatar.js +160 -0
- package/src/react/components/WebsocketListener.native.js +11 -11
- package/src/react/components/integrations/IntegrationHero/index.js +48 -0
- package/src/react/components/integrations/IntegrationHero/styles.js +57 -0
- package/src/react/components/integrations/IntegrationTabs/index.js +89 -0
- package/src/react/components/integrations/IntegrationTabs/styles.js +44 -0
- package/src/react/config/deviceConfigBootstrap.js +71 -30
- package/src/react/css/orders.js +72 -0
- package/src/react/pages/Connections.js +229 -0
- package/src/react/pages/Connections.styles.js +222 -0
- package/src/react/pages/DeviceDetailPage.js +2814 -0
- package/src/react/pages/DeviceDetailPage.styles.js +308 -0
- package/src/react/pages/Devices/currentDevice.js +194 -0
- package/src/react/pages/Devices/deviceTypes/DeviceGroupCard.js +257 -0
- package/src/react/pages/Devices/deviceTypes/all.js +23 -0
- package/src/react/pages/Devices/deviceTypes/device.js +25 -0
- package/src/react/pages/Devices/deviceTypes/deviceListHelpers.js +178 -0
- package/src/react/pages/Devices/deviceTypes/display.js +26 -0
- package/src/react/pages/Devices/deviceTypes/index.js +145 -0
- package/src/react/pages/Devices/deviceTypes/ipCamera.js +35 -0
- package/src/react/pages/Devices/deviceTypes/pdv.js +88 -0
- package/src/react/pages/Devices/deviceTypes/printer.js +37 -0
- package/src/react/pages/Devices/deviceTypes/shared.js +453 -0
- package/src/react/pages/Devices/deviceTypes/useDeviceNetworkConnectivity.js +145 -0
- package/src/react/pages/Devices.js +183 -0
- package/src/react/pages/Devices.styles.js +353 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99CatalogTab.js +219 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99OverviewTab.js +134 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99PreviewModal.js +173 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99ProductCard.js +1 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99QuickWalletModal.js +181 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99SettingsTab.js +306 -0
- package/src/react/pages/Food99IntegrationPage/components/Food99StoreTab.js +417 -0
- package/src/react/pages/Food99IntegrationPage/index.js +1530 -0
- package/src/react/pages/Food99IntegrationPage/styles.js +792 -0
- package/src/react/pages/Food99IntegrationPage/utils.js +155 -0
- package/src/react/pages/Food99IntegrationPage.js +1 -0
- package/src/react/pages/Food99IntegrationPage.styles.js +1 -0
- package/src/react/pages/GenericLogPage.js +42 -167
- package/src/react/pages/IFoodIntegrationPage/components/IFoodCatalogTab.js +8 -0
- package/src/react/pages/IFoodIntegrationPage/components/IFoodOperationsTab.js +420 -0
- package/src/react/pages/IFoodIntegrationPage/components/IFoodOverviewTab.js +118 -0
- package/src/react/pages/IFoodIntegrationPage/components/IFoodPreviewModal.js +103 -0
- package/src/react/pages/IFoodIntegrationPage/components/IFoodProductCard.js +1 -0
- package/src/react/pages/IFoodIntegrationPage/components/IFoodStoreTab.js +150 -0
- package/src/react/pages/IFoodIntegrationPage/index.js +1298 -0
- package/src/react/pages/IFoodIntegrationPage/styles.js +764 -0
- package/src/react/pages/IFoodIntegrationPage/utils.js +91 -0
- package/src/react/pages/IFoodIntegrationPage.js +1 -0
- package/src/react/pages/IFoodIntegrationPage.styles.js +1 -0
- package/src/react/pages/Imports.js +214 -166
- package/src/react/pages/IntegrationConfigPage.js +744 -0
- package/src/react/pages/IntegrationConfigPage.styles.js +269 -0
- package/src/react/pages/Integrations.js +299 -0
- package/src/react/pages/Integrations.styles.js +130 -0
- package/src/react/pages/ManagerOrderNotificationsPage.js +642 -0
- package/src/react/pages/MarketplaceIntegrationPage/components/MarketplaceProductCard.js +205 -0
- package/src/react/pages/MarketplaceIntegrationPage/components/RemoteMarketplaceMenuTab.js +335 -0
- package/src/react/pages/MarketplaceIntegrationPage/index.js +60 -0
- package/src/react/pages/MarketplaceIntegrationPage/utils.js +137 -0
- package/src/react/pages/MercadoLivreIntegrationPage.js +538 -0
- package/src/react/pages/PrinterDeviceDetailPage.js +1916 -0
- package/src/react/pages/PrinterDeviceDetailPage.styles.js +223 -0
- package/src/react/pages/PrinterDeviceFormPage.js +521 -0
- package/src/react/pages/PrinterDeviceFormPage.styles.js +159 -0
- package/src/react/pages/SettingsPage/PaymentTypesByWalletTab.js +484 -454
- package/src/react/pages/SettingsPage/index.js +1266 -1167
- package/src/react/pages/WhatsAppConnectionPage.js +459 -0
- package/src/react/pages/WhatsAppConnectionPage.styles.js +284 -0
- package/src/react/pages/integrationsCatalog.js +399 -0
- package/src/react/print/providers/local.js +1 -1
- package/src/react/router/publicRoutes.js +25 -0
- package/src/react/services/Cielo/Checkout.js +39 -0
- package/src/react/services/Cielo/Cielo.js +193 -0
- package/src/react/services/Cielo/Print.js +7 -0
- package/src/react/services/InfinitePay/Checkout.js +33 -0
- package/src/react/services/InfinitePay/InfinitePay.js +24 -0
- package/src/react/{utils → services}/paymentGatewayExecution.js +91 -91
- package/src/react/styles/global.js +115 -0
- package/src/react/utils/categoryContexts.js +46 -0
- package/src/react/utils/entityDisplay.js +222 -217
- package/src/react/utils/fileUrl.js +201 -16
- package/src/react/utils/integrationPage.js +16 -0
- package/src/react/utils/menuNavigation.js +31 -0
- package/src/react/utils/orderIdentity.js +277 -0
- package/src/react/utils/remotePayment.js +115 -61
- package/src/react/utils/runtimeFooter.js +40 -22
- package/src/react/utils/runtimeLanguage.js +50 -9
- package/src/react/utils/runtimeMenu.js +190 -98
- package/src/react/utils/runtimeZoom.js +43 -0
- package/src/react/utils/shopConfig.js +72 -34
- package/src/react/utils/shopFranchises.js +182 -23
- package/src/react/utils/socketRuntimePipeline.js +14 -14
- package/src/react/utils/storeColumns.js +23 -4
- package/src/react/utils/userAvatar.js +104 -0
- package/src/store/categories/index.js +48 -20
- package/src/store/configs/index.js +2 -2
- package/src/store/device_config/index.js +62 -21
- package/src/store/entity_log/index.js +22 -1
- package/src/store/imports/customActions.js +51 -0
- package/src/store/imports/index.js +89 -88
- package/src/store/status/index.js +11 -11
- package/src/store/themes/index.js +22 -0
- package/src/store/timezones/index.js +3 -1
- package/src/tests/browser/manager/connections.spec.js +143 -0
- package/src/tests/browser/manager/devices-current.spec.js +343 -0
- package/src/tests/browser/manager/mercado-livre-integration.spec.js +268 -0
- package/src/tests/react/api/deviceHeaders.test.js +114 -0
- package/src/tests/react/api/loadSmokeIndex.test.js +75 -0
- package/src/tests/react/components/AddImportModal.test.js +166 -0
- package/src/tests/react/components/BottomNavigationBar.config.test.js +20 -0
- package/src/tests/react/components/UserAvatar.test.js +52 -0
- package/src/tests/react/config/deviceConfigBootstrap.test.js +47 -0
- package/src/tests/react/pages/DevicePickerStyles.test.js +47 -0
- package/src/tests/react/pages/Devices/deviceListHelpers.test.js +39 -0
- package/src/tests/react/pages/DevicesCurrentDevice.test.js +198 -0
- package/src/tests/react/pages/connectionsHelpers.test.js +34 -0
- package/src/tests/react/pages/mercadoLivreIntegrationPageContract.test.mjs +16 -0
- package/src/tests/react/print/localPrintProvider.test.js +1 -1
- package/src/tests/react/services/Cielo.test.js +190 -0
- package/src/tests/react/store/categoriesOrdering.test.js +26 -0
- package/src/tests/react/utils/appDomain.test.js +62 -0
- package/src/tests/react/utils/entityDisplay.test.js +2 -2
- package/src/tests/react/utils/fileUrl.test.js +62 -0
- package/src/tests/react/utils/formatter.test.mjs +33 -0
- package/src/tests/react/utils/importStatus.test.js +2 -2
- package/src/tests/react/utils/orderIdentity.test.js +139 -0
- package/src/tests/react/utils/remotePayment.test.js +62 -0
- package/src/tests/react/utils/runtimeFooter.test.js +32 -9
- package/src/tests/react/utils/runtimeLanguage.test.js +80 -10
- package/src/tests/react/utils/runtimeMenu.test.js +195 -111
- package/src/tests/react/utils/runtimeZoom.test.js +38 -0
- package/src/tests/react/utils/shopConfig.test.js +75 -0
- package/src/tests/react/utils/shopFranchises.test.js +122 -12
- package/src/tests/react/utils/translate.discovery.test.mjs +170 -0
- package/src/tests/react/utils/translate.test.helpers.mjs +152 -0
- package/src/tests/react/utils/translate.test.mjs +252 -396
- package/src/tests/react/utils/userAvatar.test.js +63 -0
- package/src/utils/appDomain.js +15 -4
- package/src/utils/formatter.js +122 -16
- package/src/utils/integrationConfigs.js +1 -0
- package/src/utils/translate.js +277 -398
- package/src/utils/translateDiscovery.js +96 -0
- package/src/utils/translateNormalize.js +33 -0
- package/src/utils/translatePending.js +92 -0
- package/src/utils/translateStorage.js +142 -0
- package/.github/agents/developer.agent.md +0 -30
- package/.github/agents/devops.agent.md +0 -30
- package/.github/agents/qa.agent.md +0 -30
- package/.github/agents/security.agent.md +0 -30
- package/.github/workflows/npmjs.yml +0 -35
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getAvatarDisplayName,
|
|
3
|
+
getGravatarUrl,
|
|
4
|
+
getUserInitials,
|
|
5
|
+
resolveUserAvatarUrl,
|
|
6
|
+
resolveUserPeopleIri,
|
|
7
|
+
} from '../../../react/utils/userAvatar';
|
|
8
|
+
|
|
9
|
+
describe('userAvatar', () => {
|
|
10
|
+
it('uses the first and last names for two initials', () => {
|
|
11
|
+
expect(getUserInitials({name: 'Alexandre AleMac Cunha'})).toBe('AC');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('uses one initial for a single name', () => {
|
|
15
|
+
expect(getUserInitials({name: 'Alexandre'})).toBe('A');
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('falls back to the email initial when the name is unavailable', () => {
|
|
19
|
+
expect(getUserInitials({email: 'claudio@example.com'})).toBe('C');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('asks Gravatar for a real image without an identicon fallback', () => {
|
|
23
|
+
expect(getGravatarUrl(' MyEmailAddress@example.com ', 120)).toBe(
|
|
24
|
+
'https://www.gravatar.com/avatar/0bc83cb571cd1c50ba6f3e8a78ef1346?s=120&d=404',
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('does not call Gravatar without an email', () => {
|
|
29
|
+
expect(getGravatarUrl('')).toBe('');
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('uses the complete person name and never the functional alias', () => {
|
|
33
|
+
const user = {name: 'Claudio Medeiros', realname: 'Claudio Owner', alias: 'owner'};
|
|
34
|
+
|
|
35
|
+
expect(getAvatarDisplayName(user)).toBe('Claudio Medeiros');
|
|
36
|
+
expect(getUserInitials({name: getAvatarDisplayName(user)})).toBe('CM');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('resolves the person from the same stored session shape used by Profile', () => {
|
|
40
|
+
expect(
|
|
41
|
+
resolveUserPeopleIri({id: 131}, {people: '/people/14'}),
|
|
42
|
+
).toBe('/people/14');
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('resolves only the canonical persisted avatar', () => {
|
|
46
|
+
const user = {avatar: {id: 42}};
|
|
47
|
+
|
|
48
|
+
expect(
|
|
49
|
+
resolveUserAvatarUrl(user, avatar =>
|
|
50
|
+
avatar?.id ? `https://api.example/files/${avatar.id}/download` : '',
|
|
51
|
+
),
|
|
52
|
+
).toBe('https://api.example/files/42/download');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('does not treat avatarUrl as an avatar source', () => {
|
|
56
|
+
expect(
|
|
57
|
+
resolveUserAvatarUrl(
|
|
58
|
+
{avatarUrl: 'https://legacy.example/avatar.png'},
|
|
59
|
+
() => '',
|
|
60
|
+
),
|
|
61
|
+
).toBe('');
|
|
62
|
+
});
|
|
63
|
+
});
|
package/src/utils/appDomain.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
const
|
|
1
|
+
const INVALID_DOMAIN_VALUES = new Set(['undefined', 'null', 'false']);
|
|
2
|
+
|
|
3
|
+
const toRawString = value => {
|
|
4
|
+
const raw = String(value || '').trim();
|
|
5
|
+
return INVALID_DOMAIN_VALUES.has(raw.toLowerCase()) ? '' : raw;
|
|
6
|
+
};
|
|
2
7
|
|
|
3
8
|
const tryParseHost = value => {
|
|
4
9
|
const raw = toRawString(value);
|
|
@@ -23,10 +28,16 @@ export const resolveRuntimeHost = () => {
|
|
|
23
28
|
return toRawString(location?.host || '');
|
|
24
29
|
};
|
|
25
30
|
|
|
31
|
+
/**
|
|
32
|
+
* App-Domain header value.
|
|
33
|
+
* Browser (web multi-tenant): always prefer window.location.host so custom
|
|
34
|
+
* domains (e.g. erpjaguncos.com.br) resolve the correct tenant.
|
|
35
|
+
* Native / no location: fall back to configured DOMAIN from env.
|
|
36
|
+
*/
|
|
26
37
|
export const resolveAppDomain = configuredDomain => {
|
|
27
|
-
const
|
|
28
|
-
if (
|
|
29
|
-
return tryParseHost(
|
|
38
|
+
const runtimeHost = tryParseHost(resolveRuntimeHost());
|
|
39
|
+
if (runtimeHost) return runtimeHost;
|
|
40
|
+
return tryParseHost(configuredDomain);
|
|
30
41
|
};
|
|
31
42
|
|
|
32
43
|
export const resolveCompanyDomain = (company, fallbackDomain = '') => {
|
package/src/utils/formatter.js
CHANGED
|
@@ -1,10 +1,62 @@
|
|
|
1
|
-
|
|
1
|
+
/* global Intl */
|
|
2
|
+
|
|
3
|
+
const MOJIBAKE_REPLACEMENTS = [
|
|
4
|
+
['À', 'À'],
|
|
5
|
+
['\u00C3\u0081', 'Á'],
|
|
6
|
+
['Â', 'Â'],
|
|
7
|
+
['Ã', 'Ã'],
|
|
8
|
+
['É', 'É'],
|
|
9
|
+
['Ê', 'Ê'],
|
|
10
|
+
['Ó', 'Ó'],
|
|
11
|
+
['Ô', 'Ô'],
|
|
12
|
+
['Õ', 'Õ'],
|
|
13
|
+
['Ú', 'Ú'],
|
|
14
|
+
['á', 'á'],
|
|
15
|
+
['Ã ', 'à'],
|
|
16
|
+
['Ã\u00A0', 'à'],
|
|
17
|
+
['â', 'â'],
|
|
18
|
+
['ã', 'ã'],
|
|
19
|
+
['é', 'é'],
|
|
20
|
+
['ê', 'ê'],
|
|
21
|
+
['Ã', 'í'],
|
|
22
|
+
['ó', 'ó'],
|
|
23
|
+
['ô', 'ô'],
|
|
24
|
+
['õ', 'õ'],
|
|
25
|
+
['ú', 'ú'],
|
|
26
|
+
['Ç', 'Ç'],
|
|
27
|
+
['ç', 'ç'],
|
|
28
|
+
['º', 'º'],
|
|
29
|
+
['ª', 'ª'],
|
|
30
|
+
['·', '·'],
|
|
31
|
+
['→', '→'],
|
|
32
|
+
['–', '–'],
|
|
33
|
+
['—', '—'],
|
|
34
|
+
['‘', "'"],
|
|
35
|
+
['’', "'"],
|
|
36
|
+
['“', '"'],
|
|
37
|
+
['\u00E2\u20AC\u009D', '"'],
|
|
38
|
+
['Â', ''],
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
export default class Formatter {
|
|
2
42
|
|
|
3
43
|
/* ================= UTIL ================= */
|
|
4
44
|
|
|
5
|
-
static onlyNumbers(value) {
|
|
6
|
-
return String(value || '').replace(/\D/g, '');
|
|
7
|
-
}
|
|
45
|
+
static onlyNumbers(value) {
|
|
46
|
+
return String(value || '').replace(/\D/g, '');
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
static repairMojibake(value) {
|
|
50
|
+
let text = String(value || '');
|
|
51
|
+
|
|
52
|
+
for (let pass = 0; pass < 2; pass += 1) {
|
|
53
|
+
MOJIBAKE_REPLACEMENTS.forEach(([broken, fixed]) => {
|
|
54
|
+
text = text.split(broken).join(fixed);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
return text;
|
|
59
|
+
}
|
|
8
60
|
|
|
9
61
|
/* ================= DOCUMENTOS ================= */
|
|
10
62
|
|
|
@@ -310,6 +362,24 @@ export default class Formatter {
|
|
|
310
362
|
return `${Formatter.formatDecimal(value, locale, maximumFractionDigits)}%`;
|
|
311
363
|
}
|
|
312
364
|
|
|
365
|
+
static formatCount(value, singular, plural = `${singular}s`) {
|
|
366
|
+
return `${value} ${value === 1 ? singular : plural}`;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
static formatDateTime(value) {
|
|
370
|
+
if (!value) return 'sem data';
|
|
371
|
+
|
|
372
|
+
const date = new Date(value);
|
|
373
|
+
|
|
374
|
+
if (isNaN(date.getTime()))
|
|
375
|
+
return value;
|
|
376
|
+
|
|
377
|
+
return new Intl.DateTimeFormat('pt-BR', {
|
|
378
|
+
dateStyle: 'medium',
|
|
379
|
+
timeStyle: 'short',
|
|
380
|
+
}).format(date);
|
|
381
|
+
}
|
|
382
|
+
|
|
313
383
|
static formatSignedInteger(value, locale = 'pt-BR') {
|
|
314
384
|
|
|
315
385
|
const numericValue = Number(value || 0);
|
|
@@ -384,14 +454,18 @@ export default class Formatter {
|
|
|
384
454
|
return `${year}-${month}-${day}`;
|
|
385
455
|
}
|
|
386
456
|
|
|
387
|
-
static formatDateYmdTodmY(value, withTime = false) {
|
|
388
|
-
|
|
389
|
-
if (!value) return '';
|
|
390
|
-
|
|
391
|
-
const
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
457
|
+
static formatDateYmdTodmY(value, withTime = false) {
|
|
458
|
+
|
|
459
|
+
if (!value) return '';
|
|
460
|
+
|
|
461
|
+
const isoOffsetParts = Formatter.parseIsoDateWithNumericOffset(value);
|
|
462
|
+
if (isoOffsetParts)
|
|
463
|
+
return Formatter.formatDatePartsToBR(isoOffsetParts, withTime);
|
|
464
|
+
|
|
465
|
+
const date = new Date(value);
|
|
466
|
+
|
|
467
|
+
if (isNaN(date.getTime()))
|
|
468
|
+
return value;
|
|
395
469
|
|
|
396
470
|
const clientTimeZoneOffset = new Date().getTimezoneOffset();
|
|
397
471
|
|
|
@@ -412,8 +486,40 @@ export default class Formatter {
|
|
|
412
486
|
options.minute = '2-digit';
|
|
413
487
|
options.second = '2-digit';
|
|
414
488
|
}
|
|
415
|
-
|
|
416
|
-
return date.toLocaleString('pt-BR', options);
|
|
417
|
-
}
|
|
418
|
-
|
|
489
|
+
|
|
490
|
+
return date.toLocaleString('pt-BR', options);
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
static parseIsoDateWithNumericOffset(value) {
|
|
494
|
+
|
|
495
|
+
if (typeof value !== 'string')
|
|
496
|
+
return null;
|
|
497
|
+
|
|
498
|
+
const matches = value.match(
|
|
499
|
+
/^(\d{4})-(\d{2})-(\d{2})[T\s](\d{2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?[+-]\d{2}:?\d{2}$/
|
|
500
|
+
);
|
|
501
|
+
|
|
502
|
+
if (!matches)
|
|
503
|
+
return null;
|
|
504
|
+
|
|
505
|
+
return {
|
|
506
|
+
year: matches[1],
|
|
507
|
+
month: matches[2],
|
|
508
|
+
day: matches[3],
|
|
509
|
+
hour: matches[4],
|
|
510
|
+
minute: matches[5],
|
|
511
|
+
second: matches[6] || '00',
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
static formatDatePartsToBR(parts, withTime = false) {
|
|
516
|
+
|
|
517
|
+
const date = `${parts.day}/${parts.month}/${parts.year}`;
|
|
518
|
+
|
|
519
|
+
if (!withTime)
|
|
520
|
+
return date;
|
|
521
|
+
|
|
522
|
+
return `${date}, ${parts.hour}:${parts.minute}:${parts.second}`;
|
|
523
|
+
}
|
|
524
|
+
|
|
419
525
|
}
|