diff --git a/packages/components/plh/index.ts b/packages/components/plh/index.ts
index 22ff38bdc..a869e3844 100644
--- a/packages/components/plh/index.ts
+++ b/packages/components/plh/index.ts
@@ -1,19 +1,27 @@
import { PlhParentPointCounterComponent } from "./parent-point-counter/parent-point-counter.component";
import { PlhParentPointBoxComponent } from "./parent-point-box/parent-point-box.component";
import { PlhModuleListItemComponent } from "./plh-kids-kw/components/module-list-item/module-list-item.component";
+import { PlhActivityCheckInComponent } from "./plh-kids-kw/components/activity-check-in/activity-check-in.component";
-export { PlhParentPointCounterComponent, PlhParentPointBoxComponent, PlhModuleListItemComponent };
+export {
+ PlhParentPointCounterComponent,
+ PlhParentPointBoxComponent,
+ PlhModuleListItemComponent,
+ PlhActivityCheckInComponent,
+};
export const PLH_COMPONENTS = [
PlhParentPointCounterComponent,
PlhParentPointBoxComponent,
PlhModuleListItemComponent,
+ PlhActivityCheckInComponent,
];
export const PLH_COMPONENT_MAPPING = {
parent_point_counter: PlhParentPointCounterComponent,
parent_point_box: PlhParentPointBoxComponent,
plh_module_list_item: PlhModuleListItemComponent,
+ plh_activity_check_in: PlhActivityCheckInComponent,
};
export type PLHComponentName = keyof typeof PLH_COMPONENT_MAPPING;
diff --git a/packages/components/plh/plh-kids-kw/components/activity-check-in/activity-check-in.component.html b/packages/components/plh/plh-kids-kw/components/activity-check-in/activity-check-in.component.html
new file mode 100644
index 000000000..98b084857
--- /dev/null
+++ b/packages/components/plh/plh-kids-kw/components/activity-check-in/activity-check-in.component.html
@@ -0,0 +1,50 @@
+@if (daysLeft >= 1) {
+
+
+
+
+
In {{ daysLeft }} day{{ daysLeft > 1 ? "s" : "" }}
+
+
+
+
+
+
+
+
{{ params.title }}
+
+
+
+
+
+
+
+} @else {
+
+
+
+
+
+
+
+
{{ params.title }}
+
+
+
+
+
+
+
+}
diff --git a/packages/components/plh/plh-kids-kw/components/activity-check-in/activity-check-in.component.scss b/packages/components/plh/plh-kids-kw/components/activity-check-in/activity-check-in.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/packages/components/plh/plh-kids-kw/components/activity-check-in/activity-check-in.component.spec.ts b/packages/components/plh/plh-kids-kw/components/activity-check-in/activity-check-in.component.spec.ts
new file mode 100644
index 000000000..36f89a12d
--- /dev/null
+++ b/packages/components/plh/plh-kids-kw/components/activity-check-in/activity-check-in.component.spec.ts
@@ -0,0 +1,24 @@
+import { ComponentFixture, TestBed, waitForAsync } from "@angular/core/testing";
+import { IonicModule } from "@ionic/angular";
+
+import { PlhActivityCheckInComponent } from "./activity-check-in.component";
+
+describe("ActivityCheckInComponent", () => {
+ let component: PlhActivityCheckInComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(waitForAsync(() => {
+ TestBed.configureTestingModule({
+ declarations: [PlhActivityCheckInComponent],
+ imports: [IonicModule.forRoot()],
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(PlhActivityCheckInComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ }));
+
+ it("should create", () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/packages/components/plh/plh-kids-kw/components/activity-check-in/activity-check-in.component.ts b/packages/components/plh/plh-kids-kw/components/activity-check-in/activity-check-in.component.ts
new file mode 100644
index 000000000..aae901e1c
--- /dev/null
+++ b/packages/components/plh/plh-kids-kw/components/activity-check-in/activity-check-in.component.ts
@@ -0,0 +1,127 @@
+import { Component, OnInit } from "@angular/core";
+import { TemplateBaseComponent } from "src/app/shared/components/template/components/base";
+import { TemplateTranslateService } from "src/app/shared/components/template/services/template-translate.service";
+import { getNumberParamFromTemplateRow, getStringParamFromTemplateRow } from "src/app/shared/utils";
+
+interface IActivityCheckInParams {
+ /* TEMPLATE PARAMETER: "activity_id". The activity identifier attached at the bottom of the component */
+ id: string;
+ /* TEMPLATE PARAMETER: "title". The title attached at the bottom of the component */
+ title?: string;
+ /* TEMPLATE PARAMETER: "locked_icon_asset". The icon that shows when the activity is locked */
+ lockedIconAsset?: string;
+ /* TEMPLATE PARAMETER: "locked_image_asset". The illustration that shows when the activity is locked */
+ lockedImageAsset?: string;
+ /* TEMPLATE PARAMETER: "unlocked_icon_asset". The icon that shows when the activity is unlocked */
+ unlockedIconAsset?: string;
+ /* TEMPLATE PARAMETER: "unlocked_image_asset". The illustration that shows when the activity is locked */
+ unlockedImageAsset?: string;
+ /* TEMPLATE PARAMETER: "days_to_count_down". The illustration that shows when the activity is locked */
+ countDownDays?: number;
+}
+
+@Component({
+ selector: "plh-activity-check-in",
+ templateUrl: "./activity-check-in.component.html",
+ styleUrls: ["./activity-check-in.component.scss"],
+})
+export class PlhActivityCheckInComponent extends TemplateBaseComponent implements OnInit {
+ params: Partial = {};
+
+ daysLeft: number; // Progress of days left
+ progressPercentage: number = 16; // Initial progress
+
+ private unlockDate: Date;
+
+ constructor(public templateTranslateService: TemplateTranslateService) {
+ super();
+ }
+
+ ngOnInit() {
+ this.getParams();
+ this.daysLeft = this.params.countDownDays;
+ if (this._row.value) {
+ this.checkInTimer();
+ }
+ }
+
+ private getParams() {
+ this.params.id = getStringParamFromTemplateRow(this._row, "activity_id", null);
+ this.params.title = getStringParamFromTemplateRow(this._row, "title", null);
+ this.params.lockedIconAsset = getStringParamFromTemplateRow(
+ this._row,
+ "locked_icon_asset",
+ null
+ );
+ this.params.lockedImageAsset = getStringParamFromTemplateRow(
+ this._row,
+ "locked_image_asset",
+ null
+ );
+ this.params.unlockedIconAsset = getStringParamFromTemplateRow(
+ this._row,
+ "unlocked_icon_asset",
+ null
+ );
+ this.params.unlockedImageAsset = getStringParamFromTemplateRow(
+ this._row,
+ "unlocked_image_asset",
+ null
+ );
+ this.params.countDownDays = getNumberParamFromTemplateRow(this._row, "days_to_count_down", 6);
+ }
+
+ private getLocalStorageKey(): string {
+ return `activity_${this.params.id}`;
+ }
+
+ // Calculates the days until check in
+ private checkInTimer() {
+ const localStorageKey = this.getLocalStorageKey();
+ const storedDate = localStorage.getItem(localStorageKey);
+ if (storedDate) {
+ this.unlockDate = new Date(storedDate);
+ this.updateProgress();
+ } else {
+ this.unlockDate = this.getMidnightOfDate(new Date());
+ this.unlockDate.setDate(this.unlockDate.getDate() + this.params.countDownDays);
+ localStorage.setItem(localStorageKey, this.unlockDate.toISOString());
+ }
+ const dailyInterval = this.getMillisecondsUntilMidnight(); // Count until midnight
+ setTimeout(() => {
+ setInterval(() => this.updateProgress(), 24 * 60 * 60 * 1000);
+ }, dailyInterval);
+ }
+
+ // Update the progress bar and unlock state
+ private updateProgress(): void {
+ const now = this.getMidnightOfDate(new Date());
+ this.daysLeft = this.unlockDate.getTime() - now.getTime();
+
+ if (now < this.unlockDate) {
+ this.daysLeft = Math.ceil(
+ (this.unlockDate.getTime() - now.getTime()) / (24 * 60 * 60 * 1000)
+ );
+ this.progressPercentage =
+ ((this.params.countDownDays - this.daysLeft) / this.params.countDownDays) * 100;
+ } else {
+ this.progressPercentage = 16;
+ localStorage.removeItem(this.getLocalStorageKey());
+ }
+ }
+
+ // Get the number of milliseconds until midnight.
+ private getMillisecondsUntilMidnight(): number {
+ const now = new Date();
+ const midnight = this.getMidnightOfDate(now);
+ midnight.setDate(midnight.getDate() + 1);
+ return midnight.getTime() - now.getTime();
+ }
+
+ // Get the midnight of a given date.
+ private getMidnightOfDate(date: Date): Date {
+ const midnight = new Date(date);
+ midnight.setHours(0, 0, 0, 0);
+ return midnight;
+ }
+}
diff --git a/src/theme/themes/plh_kids_kw/_overrides.scss b/src/theme/themes/plh_kids_kw/_overrides.scss
index 55f1cb1a6..3596f3fb4 100644
--- a/src/theme/themes/plh_kids_kw/_overrides.scss
+++ b/src/theme/themes/plh_kids_kw/_overrides.scss
@@ -604,6 +604,84 @@ body[data-theme="plh_kids_kw"] {
}
}
+ // activity-check-in
+ plh-activity-check-in {
+ .activity-container {
+ width: 45%;
+ .wrapper {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ }
+ .progress-tracker {
+ width: 100%;
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ .wrapper {
+ width: 46%;
+ }
+ .progress-bar-container {
+ background-color: var(--ion-color-gray-200);
+ height: 14px;
+ border-radius: var(--ion-border-radius-rounded);
+ margin-right: 8px;
+ overflow: hidden;
+ width: 100%;
+ }
+ .progress-bar {
+ border-radius: var(--ion-border-radius-rounded);
+ height: 100%;
+ background-color: #e0b160;
+ transition:
+ width 0.5s ease,
+ background-color 0.5s ease;
+ }
+ .countdown-text {
+ color: var(--ion-color-gray-600);
+ font-weight: var(--font-weight-medium);
+ }
+ }
+ .image {
+ img {
+ width: 140px;
+ }
+ }
+ .unlocked .image {
+ img {
+ width: 170px;
+ }
+ }
+ .details {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ margin-top: -5px;
+ .title h4 {
+ color: var(--ion-color-gray-600);
+ font-weight: var(--font-weight-bold);
+ }
+ .icon {
+ display: flex;
+ align-items: center;
+ img {
+ width: 28px;
+ }
+ }
+ }
+ }
+ .activity-container[data-language-direction~="rtl"] {
+ .progress-tracker {
+ .progress-bar-container {
+ margin-right: 0;
+ margin-left: 6px;
+ }
+ }
+ }
+ }
+
// Radio Button Group
plh-radio-group {
.btn_triangle {