@kompasid/lit-web-components 0.8.8 → 0.8.10

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/demo/index.html CHANGED
@@ -54,6 +54,7 @@
54
54
  import '../dist/src/components/kompasid-freewall/KompasFreewall.js'
55
55
  import '../dist/src/components/kompasid-metered-wall-register/KompasMeteredWallRegister.js'
56
56
  import '../dist/src/components/kompasid-header-account/KompasHeaderAccount.js'
57
+ import '../dist/src/components/kompasid-header-notification/KompasHeaderNotification.js'
57
58
  import '../dist/src/components/kompasid-grace-period/KompasGracePeriod.js'
58
59
 
59
60
  const type = 'reguler'
@@ -103,6 +104,18 @@
103
104
  const totalGracePeriod = '5'
104
105
  const productId = 9802032
105
106
 
107
+ const getCookie = name => {
108
+ const value = `; ${document.cookie}`
109
+ const parts = value.split(`; ${name}=`)
110
+ if (parts && parts.length === 2) {
111
+ return parts.pop().split(';').shift()
112
+ }
113
+ return null
114
+ }
115
+
116
+ const accessToken = getCookie('kompas._token')
117
+ const refreshToken = getCookie('kompas._token_refresh')
118
+
106
119
  const userData = {
107
120
  userName: 'User Fullname',
108
121
  expired: 'Berakhir: 6 hari lagi',
@@ -134,6 +147,12 @@
134
147
  <div
135
148
  style="max-width: 1280px; margin: auto; display: flex;padding:0 30px"
136
149
  >
150
+ <kompasid-header-notification
151
+ style="margin-left: auto; margin-right: 5px; display: flex; align-items: center"
152
+ .accessToken=${accessToken}
153
+ .refreshToken=${refreshToken}
154
+ domain="cloud"
155
+ ></kompasid-header-notification>
137
156
  <kompasid-header-account
138
157
  .userData=${userData}
139
158
  .cart_url=${cartUrl}
@@ -161,7 +180,7 @@
161
180
  .tracker_page_domain=${trackerPageDomain}
162
181
  .metered_wall_type=${meteredWallType}
163
182
  .tracker_metered_wall_balance=${trackerMeteredWallBalance}
164
- style="margin-left: auto; height: 25px; display: flex; align-items: center"
183
+ style="margin-left: 10px; height: 25px; display: flex; align-items: center"
165
184
  ></kompasid-header-account>
166
185
  </div>
167
186
  </header>
@@ -0,0 +1,36 @@
1
+ import { LitElement } from 'lit';
2
+ import { UserNotification } from './types.js';
3
+ export declare class KompasHeaderNotification extends LitElement {
4
+ static styles: import("lit").CSSResult[];
5
+ isShowDropdown: boolean;
6
+ selectedTab: string;
7
+ notificationInfoData: UserNotification;
8
+ notificationContentData: any[];
9
+ isDataLoaded: boolean;
10
+ accessToken: string;
11
+ refreshToken: string;
12
+ domain: string;
13
+ constructor();
14
+ /**
15
+ * Function to format date
16
+ */
17
+ formatDate(date: string): string;
18
+ connectedCallback(): Promise<void>;
19
+ disconnectedCallback(): Promise<void>;
20
+ private apiFetch;
21
+ private getNotifRubrik;
22
+ private getNotifList;
23
+ private getEpaperData;
24
+ private notifRead;
25
+ private loadData;
26
+ private toggleDropdown;
27
+ private notificationIcon;
28
+ private handleClick;
29
+ private redirectTo;
30
+ private handleClickOutside;
31
+ private notificationInfoSection;
32
+ private redirectToNotification;
33
+ private notificationContentSection;
34
+ private notificationPopup;
35
+ render(): import("lit").TemplateResult<1>;
36
+ }
@@ -0,0 +1,495 @@
1
+ import { __decorate } from "tslib";
2
+ import { LitElement, html, css } from 'lit';
3
+ import { format, isToday, formatDistanceStrict, subDays } from 'date-fns';
4
+ import { id } from 'date-fns/locale/id';
5
+ import { customElement, property, state } from 'lit/decorators.js';
6
+ import { unsafeSVG } from 'lit/directives/unsafe-svg.js';
7
+ import { getFontAwesomeIcon } from '../../utils/fontawesome-setup.js';
8
+ import { TWStyles } from '../../../tailwind/tailwind.js';
9
+ import { customFetch } from './utils.js';
10
+ let KompasHeaderNotification = class KompasHeaderNotification extends LitElement {
11
+ constructor() {
12
+ super();
13
+ this.isShowDropdown = false;
14
+ this.selectedTab = 'Info';
15
+ this.notificationInfoData = {};
16
+ this.notificationContentData = [];
17
+ this.isDataLoaded = false;
18
+ this.accessToken = '';
19
+ this.refreshToken = '';
20
+ this.domain = 'id'; // 'id' | 'cloud'
21
+ this.handleClick = (value) => {
22
+ this.selectedTab = value;
23
+ };
24
+ this.redirectTo = async (notifId, link) => {
25
+ const res = await this.notifRead(notifId);
26
+ if (res.status === 200) {
27
+ this.notificationInfoData = {
28
+ ...this.notificationInfoData,
29
+ notificationList: this.notificationInfoData.notificationList
30
+ ? this.notificationInfoData.notificationList.map(notifItem => ({
31
+ ...notifItem,
32
+ isRead: notifItem.notificationId === notifId ? true : notifItem.isRead,
33
+ }))
34
+ : [],
35
+ };
36
+ }
37
+ if (link) {
38
+ const url = new URL(decodeURIComponent(link));
39
+ window.open(url, '_blank');
40
+ }
41
+ };
42
+ this.handleClickOutside = this.handleClickOutside.bind(this);
43
+ }
44
+ /**
45
+ * Function to format date
46
+ */
47
+ formatDate(date) {
48
+ // Check if the provided date is today
49
+ let result;
50
+ if (isToday(date)) {
51
+ // Return time difference if it's today (e.g., "7 hours ago")
52
+ result = `${formatDistanceStrict(date, new Date(), { locale: id })} lalu`;
53
+ }
54
+ else {
55
+ // Return formatted date (e.g., "12 Sep 2024, 09:00")
56
+ result = format(date, 'dd MMM yyyy, HH:mm', { locale: id });
57
+ }
58
+ return result;
59
+ }
60
+ async connectedCallback() {
61
+ super.connectedCallback();
62
+ this.isShowDropdown = false;
63
+ if (this.accessToken && this.refreshToken && this.domain)
64
+ await this.loadData();
65
+ document.addEventListener('click', this.handleClickOutside);
66
+ }
67
+ async disconnectedCallback() {
68
+ super.disconnectedCallback();
69
+ document.removeEventListener('click', this.handleClickOutside);
70
+ }
71
+ async apiFetch(url, options) {
72
+ const response = await customFetch(url, this.refreshToken, this.accessToken, this.domain, { ...options });
73
+ return response;
74
+ }
75
+ async getNotifRubrik() {
76
+ const req = this.apiFetch(`https://cds.kompas.${this.domain}/api/v1/article/pilihanku`, {
77
+ method: 'GET',
78
+ headers: {
79
+ 'Content-Type': 'application/json',
80
+ },
81
+ });
82
+ return req;
83
+ }
84
+ async getNotifList() {
85
+ const req = await this.apiFetch(`https://api.kompas.${this.domain}/account/api/v1/users/notification`, {
86
+ method: 'GET',
87
+ headers: {
88
+ 'Content-Type': 'application/json',
89
+ },
90
+ });
91
+ return req;
92
+ }
93
+ async getEpaperData() {
94
+ const formatDate = 'yyyy/MM/dd';
95
+ const startDate = format(subDays(new Date(), 1), formatDate);
96
+ const endDate = format(new Date(), formatDate).toString();
97
+ const req = await this.apiFetch(`https://apiepaper.kompas.${this.domain}/products?startDate=${startDate}&endDate=${endDate}&sort=desc`, {
98
+ method: 'GET',
99
+ headers: {
100
+ 'Content-Type': 'application/json',
101
+ },
102
+ });
103
+ return req;
104
+ }
105
+ async notifRead(notifId) {
106
+ const req = await this.apiFetch(`https://api.kompas.${this.domain}/account/api/v1/users/notification/read`, {
107
+ headers: {
108
+ 'Content-Type': 'application/json',
109
+ },
110
+ method: 'PUT',
111
+ body: JSON.stringify({
112
+ notificationId: notifId,
113
+ }),
114
+ });
115
+ return req;
116
+ }
117
+ async loadData() {
118
+ const apiCalls = [
119
+ this.getNotifList(),
120
+ this.getNotifRubrik(),
121
+ this.getEpaperData(),
122
+ ];
123
+ this.isDataLoaded = false;
124
+ Promise.all(apiCalls)
125
+ .then(responses => Promise.all(responses.map(response => response.json())))
126
+ .then(values => {
127
+ this.notificationInfoData = values[0].data;
128
+ this.notificationInfoData.notificationList = null;
129
+ this.notificationInfoData.notificationList =
130
+ this.notificationInfoData.notificationList || [];
131
+ const rubrikData = values[1].result || [];
132
+ const ePaperData = values[2].data[0] || {};
133
+ const { publishDate, description, thumbnail, title, url } = ePaperData;
134
+ const data = {
135
+ title,
136
+ category: [{ name: 'ePaper', slug: 'epaper' }],
137
+ publishedDateGmt: format(new Date(publishDate), 'yyyy-MM-dd HH:mm:ss'),
138
+ permalink: url,
139
+ thumbnails: {
140
+ sizes: { thumbnailSquareMedium: { permalink: thumbnail } },
141
+ },
142
+ excerpt: description,
143
+ };
144
+ this.notificationContentData = [data, ...rubrikData];
145
+ this.notificationContentData.sort((a, b) => new Date(b.publishedDateGmt).getTime() -
146
+ new Date(a.publishedDateGmt).getTime());
147
+ this.isDataLoaded = true;
148
+ });
149
+ }
150
+ toggleDropdown() {
151
+ this.isShowDropdown = !this.isShowDropdown;
152
+ }
153
+ notificationIcon() {
154
+ const notificationIndicator = () => {
155
+ if (!this.notificationInfoData.notificationCount)
156
+ return html ``;
157
+ return html `<div
158
+ class="header-account--notification-indicator animate-ping"
159
+ ></div>`;
160
+ };
161
+ return html `
162
+ <button
163
+ @click=${this.toggleDropdown}
164
+ class="cursor-pointer relative flex items-center"
165
+ >
166
+ ${notificationIndicator()}
167
+ <div class="flex flex-row items-center self-center">
168
+ <div class="text-white cursor-pointer mt-0.5">
169
+ ${unsafeSVG(getFontAwesomeIcon('fas', 'bell', 21, 21))}
170
+ </div>
171
+ </div>
172
+ </button>
173
+ `;
174
+ }
175
+ handleClickOutside(event) {
176
+ var _a;
177
+ if (!this.isShowDropdown)
178
+ return;
179
+ const popup = (_a = this.shadowRoot) === null || _a === void 0 ? void 0 : _a.getElementById('headerNotification');
180
+ const ev = event.composedPath();
181
+ if (this.isShowDropdown && popup && !(ev === null || ev === void 0 ? void 0 : ev.includes(popup))) {
182
+ this.isShowDropdown = false; // Close the popup
183
+ }
184
+ }
185
+ // Notification Info
186
+ notificationInfoSection() {
187
+ const { notificationList, } = this.notificationInfoData;
188
+ // Empty state
189
+ if (!notificationList || !notificationList.length)
190
+ return html `
191
+ <div class="text-center px-4 pt-6 pb-18">
192
+ <img
193
+ src="../../assets/empty-state-notification.png"
194
+ alt="empty-state-notification"
195
+ class="w-auto mx-auto"
196
+ />
197
+ <p class="font-bold text-center text-lg py-2">Belum Ada Notifikasi</p>
198
+ <p class="px-2">
199
+ Kami akan memberitahukan Anda ketika ada informasi dan pemberitahuan
200
+ terbaru.
201
+ </p>
202
+ </div>
203
+ `;
204
+ const notificationInfoListTemplate = (item) => {
205
+ const imgUrl = item.label === 'Akun'
206
+ ? `https://cdn-www.kompas.id/assets/notifikasi-akun.svg`
207
+ : `https://cdn-www.kompas.id/assets/langganan-anda-telah-berakhir.svg`;
208
+ return html `<div class="w-3/4 pr-1">
209
+ <div class="flex items-center mb-1 text-xs">
210
+ <span class="text-green-500 bg-green-100 rounded-sm p-1 px-2">
211
+ ${item.label}
212
+ </span>
213
+ <span class="text-grey-400 ml-2"
214
+ >${this.formatDate(item.time)}</span
215
+ >
216
+ </div>
217
+ <div>
218
+ <p class="text-sm font-bold">${item.title}</p>
219
+ <p class="text-sm">${item.description}</p>
220
+ </div>
221
+ </div>
222
+ <div class="w-1/4">
223
+ <img src="${imgUrl}" alt="${item.label}-alt" class="w-14 h-14" />
224
+ </div>`;
225
+ };
226
+ return html `<div class="h-[300px] overflow-y-scroll">
227
+ ${notificationList.map(item => html `<button
228
+ class="flex w-full text-left items-start p-4 cursor-pointer justify-between ${!item.isRead
229
+ ? 'bg-blue-100'
230
+ : ''}"
231
+ @click=${() => this.redirectTo(item.notificationId, item.link)}
232
+ >
233
+ ${notificationInfoListTemplate(item)}
234
+ </button> `)}
235
+ </div>
236
+ <!-- Footer Link -->
237
+ <div class="px-4 py-4 text-center">
238
+ <a href="#" @click="${() => this.redirectToNotification('info')}" class="text-base font-bold text-blue-500">
239
+ Lihat Selengkapnya</a
240
+ >
241
+ </div>
242
+ </div>`;
243
+ }
244
+ redirectToNotification(tab) {
245
+ window.open(`https://account.kompas.id/manage-account/notification/${tab}`, '_blank');
246
+ }
247
+ // Notification Content
248
+ notificationContentSection() {
249
+ // Empty state
250
+ if (!this.notificationContentData.length) {
251
+ return html `
252
+ <div class="text-center px-4 pt-6 pb-18">
253
+ <img
254
+ src="../../assets/empty-state-notification.png"
255
+ alt="empty-state-notification"
256
+ class="w-auto mx-auto"
257
+ />
258
+ <p class="font-bold text-center text-lg py-2">Belum Ada Notifikasi</p>
259
+ <p class="px-2">
260
+ Kami akan memberitahukan Anda ketika ada informasi dan pemberitahuan
261
+ terbaru.
262
+ </p>
263
+ </div>
264
+ `;
265
+ }
266
+ const notificationContentListTemplate = (item) => html `<div
267
+ class="w-3/4 pr-1 "
268
+ >
269
+ <div class="flex items-center mb-1 text-xs">
270
+ <span class="text-green-500 bg-green-100 rounded-sm p-1 px-2">
271
+ ${item.category[0].name}
272
+ </span>
273
+ <span class="text-grey-400 ml-2">
274
+ ${this.formatDate(item.publishedDateGmt)}</span
275
+ >
276
+ </div>
277
+ <p class="font-bold text-base text-customTextColor py-1">
278
+ ${item.title}
279
+ </p>
280
+ </div>
281
+ <div class="w-1/4">
282
+ <img
283
+ src="${item.thumbnails.sizes.thumbnailSquareMedium.permalink}"
284
+ alt="content-img-alt"
285
+ class="w-14 h-14 object-cover"
286
+ />
287
+ </div>`;
288
+ return html `<div class="h-[300px] overflow-y-scroll">
289
+ ${this.notificationContentData.map(item => html `<button
290
+ class="flex w-full text-left items-start p-4 cursor-pointer justify-between ${!item.isRead
291
+ ? 'bg-blue-100'
292
+ : ''}"
293
+ @click=${() => window.open(item.permalink, '_blank')}
294
+ >
295
+ ${notificationContentListTemplate(item)}
296
+ </button> `)}
297
+ </div>
298
+ <!-- Footer Link -->
299
+ <div class="px-4 py-4 text-center">
300
+ <a href="#" @click="${() => this.redirectToNotification('konten')}" class="text-base font-bold text-blue-500">
301
+ Lihat Selengkapnya</a
302
+ >
303
+ </div>
304
+ </div>`;
305
+ }
306
+ notificationPopup() {
307
+ const tab = ['Info', 'Konten'];
308
+ return html `
309
+ <div
310
+ id="notificationPopup"
311
+ class="header-notificaion-dropdown rounded-lg shadow-lg z-50 mt-2 ${this
312
+ .isShowDropdown
313
+ ? 'active'
314
+ : ''}"
315
+ >
316
+ <div class="sticky">
317
+ <div class="flex justify-center py-2 border-b border-grey-300">
318
+ <span class="font-bold text-base">Notifikasi</span>
319
+ </div>
320
+ <!-- Tabs for Info and Content -->
321
+ <div class="flex justify-between">
322
+ ${tab.map(item => html `
323
+ <button
324
+ class="focus:outline-none py-2 w-1/2 ${this.selectedTab ===
325
+ item && 'link-active'}"
326
+ @click=${() => this.handleClick(item)}
327
+ >
328
+ ${item}
329
+ </button>
330
+ `)}
331
+ </div>
332
+ </div>
333
+
334
+ <!-- Notification Content -->
335
+ ${this.selectedTab === 'Info'
336
+ ? this.notificationInfoSection()
337
+ : this.notificationContentSection()}
338
+ </div>
339
+ `;
340
+ }
341
+ render() {
342
+ return html `<div id="headerNotification" class="relative">
343
+ ${this.isDataLoaded
344
+ ? this.notificationIcon()
345
+ : html `<div class="text-white cursor-pointer mt-0.5 animate-spin">
346
+ ${unsafeSVG(getFontAwesomeIcon('fa', 'circle-notch', 21, 21))}
347
+ </div>`}
348
+ ${this.isShowDropdown ? this.notificationPopup() : ''}
349
+ </div>`;
350
+ }
351
+ };
352
+ KompasHeaderNotification.styles = [
353
+ css `
354
+ :host {
355
+ font-family: 'PT Sans', sans-serif;
356
+ }
357
+
358
+ .header-account--notification-indicator {
359
+ position: absolute;
360
+ top: 0;
361
+ height: 0.5rem;
362
+ width: 0.5rem;
363
+ background-color: #ff7a00;
364
+ border-radius: 50%;
365
+ right: -0.403rem;
366
+ top: -0.281rem;
367
+ }
368
+
369
+ .header-notificaion-dropdown {
370
+ width: 20.5rem;
371
+ background-color: #ffffff;
372
+ font-family: 'PT Sans', sans-serif;
373
+ font-size: 0.875rem;
374
+ position: absolute;
375
+ right: -7.5vmax;
376
+ }
377
+
378
+ .w-14 {
379
+ width: 3.25rem;
380
+ }
381
+
382
+ .pb-18 {
383
+ padding-bottom: 4.5rem;
384
+ }
385
+
386
+ .h-\\[300px\\] {
387
+ height: 300px;
388
+ }
389
+
390
+ .h-14 {
391
+ height: 3.25rem;
392
+ }
393
+
394
+ .bg-green-100 {
395
+ --tw-bg-opacity: 1;
396
+ background-color: rgb(238 252 210 / var(--tw-bg-opacity));
397
+ }
398
+
399
+ .overflow-y-scroll {
400
+ overflow-y: scroll;
401
+ }
402
+
403
+ .link-active {
404
+ color: #0468cb;
405
+ border-color: #0468cb;
406
+ border-bottom-width: 3px;
407
+ background-color: transparent !important;
408
+ }
409
+
410
+ .animate-spin {
411
+ animation: spin 2s linear infinite;
412
+ }
413
+
414
+ @keyframes spin {
415
+ from {
416
+ transform: rotate(0deg);
417
+ }
418
+ to {
419
+ transform: rotate(360deg);
420
+ }
421
+ }
422
+
423
+ .object-cover {
424
+ object-fit: cover;
425
+ }
426
+
427
+ .z-index-max {
428
+ z-index: 99999;
429
+ }
430
+
431
+ /* Custom Scrollbar for header */
432
+ /* width */
433
+ ::-webkit-scrollbar {
434
+ width: 4px;
435
+ }
436
+
437
+ /* Track */
438
+ ::-webkit-scrollbar-track {
439
+ background: transparent;
440
+ }
441
+
442
+ /* Handle */
443
+ ::-webkit-scrollbar-thumb {
444
+ background: #0356a8;
445
+ border-radius: 100px;
446
+ }
447
+
448
+ /* Handle on hover */
449
+ ::-webkit-scrollbar-thumb:hover {
450
+ background: #0356a8;
451
+ }
452
+
453
+ @media (min-width: 1024px) {
454
+ .header-notificaion-dropdown {
455
+ right: -4vmax;
456
+ }
457
+ }
458
+
459
+ @media (max-width: 360px) {
460
+ .header-notificaion-dropdown {
461
+ right: -10vmax;
462
+ }
463
+ }
464
+ `,
465
+ TWStyles,
466
+ ];
467
+ __decorate([
468
+ state()
469
+ ], KompasHeaderNotification.prototype, "isShowDropdown", void 0);
470
+ __decorate([
471
+ state()
472
+ ], KompasHeaderNotification.prototype, "selectedTab", void 0);
473
+ __decorate([
474
+ state()
475
+ ], KompasHeaderNotification.prototype, "notificationInfoData", void 0);
476
+ __decorate([
477
+ state()
478
+ ], KompasHeaderNotification.prototype, "notificationContentData", void 0);
479
+ __decorate([
480
+ state()
481
+ ], KompasHeaderNotification.prototype, "isDataLoaded", void 0);
482
+ __decorate([
483
+ property({ type: String })
484
+ ], KompasHeaderNotification.prototype, "accessToken", void 0);
485
+ __decorate([
486
+ property({ type: String })
487
+ ], KompasHeaderNotification.prototype, "refreshToken", void 0);
488
+ __decorate([
489
+ property({ type: String })
490
+ ], KompasHeaderNotification.prototype, "domain", void 0);
491
+ KompasHeaderNotification = __decorate([
492
+ customElement('kompasid-header-notification')
493
+ ], KompasHeaderNotification);
494
+ export { KompasHeaderNotification };
495
+ //# sourceMappingURL=KompasHeaderNotification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"KompasHeaderNotification.js","sourceRoot":"","sources":["../../../../src/components/kompasid-header-notification/KompasHeaderNotification.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css } from 'lit'\nimport { format, isToday, formatDistanceStrict, subDays } from 'date-fns'\nimport { id } from 'date-fns/locale/id'\nimport { customElement, property, state } from 'lit/decorators.js'\nimport { unsafeSVG } from 'lit/directives/unsafe-svg.js'\nimport { getFontAwesomeIcon } from '../../utils/fontawesome-setup.js'\nimport { TWStyles } from '../../../tailwind/tailwind.js'\nimport {\n UserNotification,\n NotificationList,\n ApiResponse,\n ApiRubrikResponse,\n} from './types.js'\nimport { customFetch } from './utils.js'\n\n@customElement('kompasid-header-notification')\nexport class KompasHeaderNotification extends LitElement {\n static styles = [\n css`\n :host {\n font-family: 'PT Sans', sans-serif;\n }\n\n .header-account--notification-indicator {\n position: absolute;\n top: 0;\n height: 0.5rem;\n width: 0.5rem;\n background-color: #ff7a00;\n border-radius: 50%;\n right: -0.403rem;\n top: -0.281rem;\n }\n\n .header-notificaion-dropdown {\n width: 20.5rem;\n background-color: #ffffff;\n font-family: 'PT Sans', sans-serif;\n font-size: 0.875rem;\n position: absolute;\n right: -7.5vmax;\n }\n\n .w-14 {\n width: 3.25rem;\n }\n\n .pb-18 {\n padding-bottom: 4.5rem;\n }\n\n .h-\\\\[300px\\\\] {\n height: 300px;\n }\n\n .h-14 {\n height: 3.25rem;\n }\n\n .bg-green-100 {\n --tw-bg-opacity: 1;\n background-color: rgb(238 252 210 / var(--tw-bg-opacity));\n }\n\n .overflow-y-scroll {\n overflow-y: scroll;\n }\n\n .link-active {\n color: #0468cb;\n border-color: #0468cb;\n border-bottom-width: 3px;\n background-color: transparent !important;\n }\n\n .animate-spin {\n animation: spin 2s linear infinite;\n }\n\n @keyframes spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n }\n\n .object-cover {\n object-fit: cover;\n }\n\n .z-index-max {\n z-index: 99999;\n }\n\n /* Custom Scrollbar for header */\n /* width */\n ::-webkit-scrollbar {\n width: 4px;\n }\n\n /* Track */\n ::-webkit-scrollbar-track {\n background: transparent;\n }\n\n /* Handle */\n ::-webkit-scrollbar-thumb {\n background: #0356a8;\n border-radius: 100px;\n }\n\n /* Handle on hover */\n ::-webkit-scrollbar-thumb:hover {\n background: #0356a8;\n }\n\n @media (min-width: 1024px) {\n .header-notificaion-dropdown {\n right: -4vmax;\n }\n }\n\n @media (max-width: 360px) {\n .header-notificaion-dropdown {\n right: -10vmax;\n }\n }\n `,\n TWStyles,\n ]\n\n @state() isShowDropdown: boolean = false\n @state() selectedTab: string = 'Info'\n @state() notificationInfoData: UserNotification = {} as UserNotification\n @state() notificationContentData: any[] = []\n @state() isDataLoaded: boolean = false\n\n @property({ type: String }) accessToken = ''\n @property({ type: String }) refreshToken = ''\n @property({ type: String }) domain = 'id' // 'id' | 'cloud'\n\n constructor() {\n super()\n this.handleClickOutside = this.handleClickOutside.bind(this)\n }\n\n /**\n * Function to format date\n */\n formatDate(date: string) {\n // Check if the provided date is today\n let result\n if (isToday(date)) {\n // Return time difference if it's today (e.g., \"7 hours ago\")\n result = `${formatDistanceStrict(date, new Date(), { locale: id })} lalu`\n } else {\n // Return formatted date (e.g., \"12 Sep 2024, 09:00\")\n result = format(date, 'dd MMM yyyy, HH:mm', { locale: id })\n }\n return result\n }\n\n override async connectedCallback() {\n super.connectedCallback()\n this.isShowDropdown = false\n\n if (this.accessToken && this.refreshToken && this.domain)\n await this.loadData()\n document.addEventListener('click', this.handleClickOutside)\n }\n\n override async disconnectedCallback() {\n super.disconnectedCallback()\n document.removeEventListener('click', this.handleClickOutside)\n }\n\n private async apiFetch(url: string, options: any) {\n const response = await customFetch(\n url,\n this.refreshToken,\n this.accessToken,\n this.domain,\n { ...options }\n )\n\n return response\n }\n\n private async getNotifRubrik() {\n const req = this.apiFetch(\n `https://cds.kompas.${this.domain}/api/v1/article/pilihanku`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n }\n )\n return req\n }\n\n private async getNotifList() {\n const req = await this.apiFetch(\n `https://api.kompas.${this.domain}/account/api/v1/users/notification`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n }\n )\n return req\n }\n\n private async getEpaperData() {\n const formatDate = 'yyyy/MM/dd'\n const startDate = format(subDays(new Date(), 1), formatDate)\n const endDate = format(new Date(), formatDate).toString()\n const req = await this.apiFetch(\n `https://apiepaper.kompas.${this.domain}/products?startDate=${startDate}&endDate=${endDate}&sort=desc`,\n {\n method: 'GET',\n headers: {\n 'Content-Type': 'application/json',\n },\n }\n )\n\n return req\n }\n\n private async notifRead(notifId: string) {\n const req = await this.apiFetch(\n `https://api.kompas.${this.domain}/account/api/v1/users/notification/read`,\n {\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'PUT',\n body: JSON.stringify({\n notificationId: notifId,\n }),\n }\n )\n return req\n }\n\n private async loadData() {\n const apiCalls = [\n this.getNotifList(),\n this.getNotifRubrik(),\n this.getEpaperData(),\n ]\n this.isDataLoaded = false\n\n Promise.all(apiCalls)\n .then(responses =>\n Promise.all(responses.map(response => response.json()))\n )\n .then(values => {\n this.notificationInfoData = (\n values[0] as ApiResponse<UserNotification>\n ).data\n this.notificationInfoData.notificationList = null\n this.notificationInfoData.notificationList =\n this.notificationInfoData.notificationList || []\n\n const rubrikData = (values[1] as ApiRubrikResponse<any>).result || []\n const ePaperData = (values[2] as ApiResponse<any>).data[0] || {}\n\n const { publishDate, description, thumbnail, title, url } = ePaperData\n\n const data = {\n title,\n category: [{ name: 'ePaper', slug: 'epaper' }],\n publishedDateGmt: format(\n new Date(publishDate),\n 'yyyy-MM-dd HH:mm:ss'\n ),\n permalink: url,\n thumbnails: {\n sizes: { thumbnailSquareMedium: { permalink: thumbnail } },\n },\n excerpt: description,\n }\n\n this.notificationContentData = [data, ...rubrikData]\n this.notificationContentData.sort(\n (a: any, b: any) =>\n new Date(b.publishedDateGmt).getTime() -\n new Date(a.publishedDateGmt).getTime()\n )\n\n this.isDataLoaded = true\n })\n }\n\n private toggleDropdown() {\n this.isShowDropdown = !this.isShowDropdown\n }\n\n private notificationIcon() {\n const notificationIndicator = () => {\n if (!this.notificationInfoData.notificationCount) return html``\n return html`<div\n class=\"header-account--notification-indicator animate-ping\"\n ></div>`\n }\n\n return html`\n <button\n @click=${this.toggleDropdown}\n class=\"cursor-pointer relative flex items-center\"\n >\n ${notificationIndicator()}\n <div class=\"flex flex-row items-center self-center\">\n <div class=\"text-white cursor-pointer mt-0.5\">\n ${unsafeSVG(getFontAwesomeIcon('fas', 'bell', 21, 21))}\n </div>\n </div>\n </button>\n `\n }\n\n private handleClick = (value: string) => {\n this.selectedTab = value\n }\n\n private redirectTo = async (notifId: string, link: string) => {\n const res = await this.notifRead(notifId)\n\n if (res.status === 200) {\n this.notificationInfoData = {\n ...this.notificationInfoData,\n notificationList: this.notificationInfoData.notificationList\n ? this.notificationInfoData.notificationList.map(notifItem => ({\n ...notifItem,\n isRead:\n notifItem.notificationId === notifId ? true : notifItem.isRead,\n }))\n : [],\n }\n }\n\n if (link) {\n const url = new URL(decodeURIComponent(link))\n\n window.open(url, '_blank')\n }\n }\n\n private handleClickOutside(event: Event) {\n if (!this.isShowDropdown) return\n\n const popup = this.shadowRoot?.getElementById('headerNotification')\n const ev = event.composedPath()\n if (this.isShowDropdown && popup && !ev?.includes(popup as HTMLElement)) {\n this.isShowDropdown = false // Close the popup\n }\n }\n\n // Notification Info\n private notificationInfoSection() {\n const {\n notificationList,\n }: { notificationList: NotificationList[] | null } =\n this.notificationInfoData\n\n // Empty state\n if (!notificationList || !notificationList.length)\n return html`\n <div class=\"text-center px-4 pt-6 pb-18\">\n <img\n src=\"../../assets/empty-state-notification.png\"\n alt=\"empty-state-notification\"\n class=\"w-auto mx-auto\"\n />\n <p class=\"font-bold text-center text-lg py-2\">Belum Ada Notifikasi</p>\n <p class=\"px-2\">\n Kami akan memberitahukan Anda ketika ada informasi dan pemberitahuan\n terbaru.\n </p>\n </div>\n `\n\n const notificationInfoListTemplate = (item: NotificationList) => {\n const imgUrl =\n item.label === 'Akun'\n ? `https://cdn-www.kompas.id/assets/notifikasi-akun.svg`\n : `https://cdn-www.kompas.id/assets/langganan-anda-telah-berakhir.svg`\n\n return html`<div class=\"w-3/4 pr-1\">\n <div class=\"flex items-center mb-1 text-xs\">\n <span class=\"text-green-500 bg-green-100 rounded-sm p-1 px-2\">\n ${item.label}\n </span>\n <span class=\"text-grey-400 ml-2\"\n >${this.formatDate(item.time)}</span\n >\n </div>\n <div>\n <p class=\"text-sm font-bold\">${item.title}</p>\n <p class=\"text-sm\">${item.description}</p>\n </div>\n </div>\n <div class=\"w-1/4\">\n <img src=\"${imgUrl}\" alt=\"${item.label}-alt\" class=\"w-14 h-14\" />\n </div>`\n }\n\n return html`<div class=\"h-[300px] overflow-y-scroll\">\n ${notificationList.map(\n item =>\n html`<button\n class=\"flex w-full text-left items-start p-4 cursor-pointer justify-between ${!item.isRead\n ? 'bg-blue-100'\n : ''}\"\n @click=${() => this.redirectTo(item.notificationId, item.link)}\n >\n ${notificationInfoListTemplate(item)}\n </button> `\n )}\n </div>\n <!-- Footer Link -->\n <div class=\"px-4 py-4 text-center\">\n <a href=\"#\" @click=\"${() =>\n this.redirectToNotification(\n 'info'\n )}\" class=\"text-base font-bold text-blue-500\">\n Lihat Selengkapnya</a\n >\n </div>\n </div>`\n }\n\n private redirectToNotification(tab: string) {\n window.open(\n `https://account.kompas.id/manage-account/notification/${tab}`,\n '_blank'\n )\n }\n\n // Notification Content\n private notificationContentSection() {\n // Empty state\n if (!this.notificationContentData.length) {\n return html`\n <div class=\"text-center px-4 pt-6 pb-18\">\n <img\n src=\"../../assets/empty-state-notification.png\"\n alt=\"empty-state-notification\"\n class=\"w-auto mx-auto\"\n />\n <p class=\"font-bold text-center text-lg py-2\">Belum Ada Notifikasi</p>\n <p class=\"px-2\">\n Kami akan memberitahukan Anda ketika ada informasi dan pemberitahuan\n terbaru.\n </p>\n </div>\n `\n }\n const notificationContentListTemplate = (item: any) => html`<div\n class=\"w-3/4 pr-1 \"\n >\n <div class=\"flex items-center mb-1 text-xs\">\n <span class=\"text-green-500 bg-green-100 rounded-sm p-1 px-2\">\n ${item.category[0].name}\n </span>\n <span class=\"text-grey-400 ml-2\">\n ${this.formatDate(item.publishedDateGmt)}</span\n >\n </div>\n <p class=\"font-bold text-base text-customTextColor py-1\">\n ${item.title}\n </p>\n </div>\n <div class=\"w-1/4\">\n <img\n src=\"${item.thumbnails.sizes.thumbnailSquareMedium.permalink}\"\n alt=\"content-img-alt\"\n class=\"w-14 h-14 object-cover\"\n />\n </div>`\n\n return html`<div class=\"h-[300px] overflow-y-scroll\">\n ${this.notificationContentData.map(\n item =>\n html`<button\n class=\"flex w-full text-left items-start p-4 cursor-pointer justify-between ${!item.isRead\n ? 'bg-blue-100'\n : ''}\"\n @click=${() => window.open(item.permalink, '_blank')}\n >\n ${notificationContentListTemplate(item)}\n </button> `\n )}\n </div>\n <!-- Footer Link -->\n <div class=\"px-4 py-4 text-center\">\n <a href=\"#\" @click=\"${() =>\n this.redirectToNotification(\n 'konten'\n )}\" class=\"text-base font-bold text-blue-500\">\n Lihat Selengkapnya</a\n >\n </div>\n </div>`\n }\n\n private notificationPopup() {\n const tab = ['Info', 'Konten']\n\n return html`\n <div\n id=\"notificationPopup\"\n class=\"header-notificaion-dropdown rounded-lg shadow-lg z-50 mt-2 ${this\n .isShowDropdown\n ? 'active'\n : ''}\"\n >\n <div class=\"sticky\">\n <div class=\"flex justify-center py-2 border-b border-grey-300\">\n <span class=\"font-bold text-base\">Notifikasi</span>\n </div>\n <!-- Tabs for Info and Content -->\n <div class=\"flex justify-between\">\n ${tab.map(\n item =>\n html`\n <button\n class=\"focus:outline-none py-2 w-1/2 ${this.selectedTab ===\n item && 'link-active'}\"\n @click=${() => this.handleClick(item)}\n >\n ${item}\n </button>\n `\n )}\n </div>\n </div>\n\n <!-- Notification Content -->\n ${this.selectedTab === 'Info'\n ? this.notificationInfoSection()\n : this.notificationContentSection()}\n </div>\n `\n }\n\n render() {\n return html`<div id=\"headerNotification\" class=\"relative\">\n ${this.isDataLoaded\n ? this.notificationIcon()\n : html`<div class=\"text-white cursor-pointer mt-0.5 animate-spin\">\n ${unsafeSVG(getFontAwesomeIcon('fa', 'circle-notch', 21, 21))}\n </div>`}\n ${this.isShowDropdown ? this.notificationPopup() : ''}\n </div>`\n }\n}\n"]}
@@ -0,0 +1,35 @@
1
+ export interface NotificationList {
2
+ notificationId: string;
3
+ id: number;
4
+ title: string;
5
+ label: string;
6
+ description: string;
7
+ isRead: boolean;
8
+ time: string;
9
+ link: string;
10
+ }
11
+ export interface UserNotification {
12
+ notificationList: NotificationList[] | null;
13
+ notificationCount: number;
14
+ loadMore: boolean;
15
+ next: number;
16
+ }
17
+ interface Meta {
18
+ cache: boolean;
19
+ time: number;
20
+ }
21
+ export interface ApiResponse<T> {
22
+ success: boolean;
23
+ code: number;
24
+ message: string;
25
+ meta: Meta;
26
+ data: T;
27
+ }
28
+ export interface ApiRubrikResponse<T> {
29
+ success: boolean;
30
+ code: number;
31
+ message: string;
32
+ meta: Meta;
33
+ result: T;
34
+ }
35
+ export {};
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map