unictive-angular 1.0.42 → 1.0.45

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.
@@ -13,13 +13,14 @@ definitions:
13
13
  - node
14
14
  script:
15
15
  - npm install -g wrangler # Install Wrangler CLI versi terbaru
16
- - npm install --force # Install dependencies dari package.json di root
16
+ - npm install --legacy-peer-deps # Install dependencies dari package.json di root
17
17
  - npm run build
18
18
  - cd workers-site
19
19
  - npm install
20
20
  - ls
21
21
  - cd ../
22
- - CLOUDFLARE_API_TOKEN=$CF_API_TOKEN wrangler deploy --config wrangler.toml
22
+ - CLOUDFLARE_API_TOKEN=$CF_API_TOKEN wrangler deploy --config
23
+ wrangler.toml
23
24
 
24
25
  clone:
25
26
  depth: full # Clone seluruh history git (diperlukan SonarQube)
@@ -90,14 +90,8 @@ export class AuthService extends AbstractApiService<any> {
90
90
  })
91
91
 
92
92
  return Entity_User.load(async () => {
93
- let isRole = null;
94
- await this.helper.getStorage('role').then((res) => {
95
- if (res) {
96
- isRole = res;
97
- }
98
- });
99
93
 
100
- const res = await this.get(isRole ? `/refresh?role=${isRole}` : '/refresh');
94
+ const res = await this.get('/refresh');
101
95
  if (res) {
102
96
  this.setLogin(true);
103
97
  this.helper.setStorage('users', res?.data?.user);
@@ -0,0 +1,209 @@
1
+ import { signal, computed } from '@angular/core';
2
+
3
+ export interface PaginationMeta {
4
+ current_page: number;
5
+ from: number;
6
+ last_page: number;
7
+ per_page: number;
8
+ to: number;
9
+ total: number;
10
+ }
11
+
12
+ export interface PaginatedResponse<T, M = PaginationMeta> {
13
+ data: T[];
14
+ meta: M;
15
+ }
16
+
17
+ export interface EntityState<T, M = PaginationMeta> {
18
+ value: T[];
19
+ loading: boolean;
20
+ error?: string;
21
+ meta?: M;
22
+ }
23
+
24
+ export function ListStoreFactory<
25
+ T extends Record<any, any>,
26
+ M extends PaginationMeta = PaginationMeta,
27
+ K extends keyof T = 'id'
28
+ >(keyField?: K | any) {
29
+
30
+ const field = (keyField ?? ('id' as K));
31
+
32
+ const _state = signal<EntityState<T, M>>({
33
+ value: [],
34
+ loading: false,
35
+ });
36
+
37
+ // ========================
38
+ // Computed Selectors
39
+ // ========================
40
+
41
+ const all = computed(() => _state().value);
42
+ const count = computed(() => _state().value.length);
43
+ const meta = computed(() => _state().meta);
44
+ const loading = computed(() => _state().loading);
45
+ const error = computed(() => _state().error);
46
+
47
+ const hasNextPage = computed(() => {
48
+ const m = _state().meta;
49
+ if (!m) return false;
50
+ return m.current_page < m.last_page;
51
+ });
52
+
53
+ const currentPage = computed(() => _state().meta?.current_page ?? 1);
54
+
55
+ const mapByKey = computed(() => {
56
+ const map = new Map<T[K], T>();
57
+ for (const item of _state().value) {
58
+ map.set(item[field], item);
59
+ }
60
+ return map;
61
+ });
62
+
63
+ const getByKey = (key: T[K]) =>
64
+ computed(() => mapByKey().get(key));
65
+
66
+ // ========================
67
+ // Private Helpers
68
+ // ========================
69
+
70
+ function deduplicate(items: T[]): T[] {
71
+ const map = new Map<T[K], T>();
72
+ for (const item of items) {
73
+ map.set(item[field], item);
74
+ }
75
+ return Array.from(map.values());
76
+ }
77
+
78
+ function setLoading(value: boolean) {
79
+ _state.update(s => ({ ...s, loading: value }));
80
+ }
81
+
82
+ function setError(message?: string) {
83
+ _state.update(s => ({ ...s, error: message }));
84
+ }
85
+
86
+ // ========================
87
+ // Public API
88
+ // ========================
89
+
90
+ async function loadPage(
91
+ page: number,
92
+ fetchFn: (page: number) => Promise<PaginatedResponse<T, M>>
93
+ ) {
94
+ setLoading(true);
95
+ setError(undefined);
96
+
97
+ try {
98
+ const response = await fetchFn(page);
99
+
100
+ console.log(response);
101
+ _state.update(curr => ({
102
+ value: page === 1
103
+ ? response.data
104
+ : deduplicate([...curr.value, ...response.data]),
105
+ meta: response.meta,
106
+ loading: false,
107
+ }));
108
+
109
+ return response;
110
+ } catch (err: any) {
111
+ setLoading(false);
112
+ setError(err?.message ?? 'Unknown error');
113
+ return null;
114
+ }
115
+ }
116
+
117
+ // --- Async Loader ---
118
+ async function load(
119
+ page: number,
120
+ fetchFn: (page: number) => Promise<PaginatedResponse<T, M>>
121
+ ) {
122
+ _state.update((curr) => ({
123
+ ...curr,
124
+ loading: true,
125
+ error: undefined,
126
+ }));
127
+ try {
128
+ const response = await fetchFn(page);
129
+ // console.log('Entity Store Loaded Data:', data);
130
+ _state.set({ value: response.data, meta: response.meta, loading: false });
131
+ return response.data;
132
+ } catch (err: any) {
133
+ _state.update((curr) => ({
134
+ ...curr,
135
+ loading: false,
136
+ error: err.message ?? 'Unknown error',
137
+ }));
138
+ return [];
139
+ }
140
+ }
141
+
142
+
143
+
144
+ async function loadNextPage(
145
+ fetchFn: (page: number) => Promise<PaginatedResponse<T, M>>
146
+ ) {
147
+ if (!hasNextPage() || loading()) return;
148
+
149
+ const nextPage = currentPage() + 1;
150
+ return loadPage(nextPage, fetchFn);
151
+ }
152
+
153
+ async function refresh(
154
+ fetchFn: (page: number) => Promise<PaginatedResponse<T, M>>
155
+ ) {
156
+ return loadPage(1, fetchFn);
157
+ }
158
+
159
+ function reset() {
160
+ _state.set({
161
+ value: [],
162
+ loading: false,
163
+ });
164
+ }
165
+
166
+ function clear() {
167
+ reset();
168
+ }
169
+
170
+ function update(key: T[K], partial: Partial<T>) {
171
+ _state.update(curr => ({
172
+ ...curr,
173
+ value: curr.value.map(i =>
174
+ i[field] === key ? { ...i, ...partial } : i
175
+ ),
176
+ }));
177
+ }
178
+
179
+ function remove(key: T[K]) {
180
+ _state.update(curr => ({
181
+ ...curr,
182
+ value: curr.value.filter(i => i[field] !== key),
183
+ }));
184
+ }
185
+
186
+ return {
187
+ state: _state,
188
+
189
+ // selectors
190
+ all,
191
+ count,
192
+ meta,
193
+ loading,
194
+ error,
195
+ hasNextPage,
196
+ currentPage,
197
+ getByKey,
198
+
199
+ // actions
200
+ load,
201
+ loadPage,
202
+ loadNextPage,
203
+ refresh,
204
+ update,
205
+ remove,
206
+ reset,
207
+ clear,
208
+ };
209
+ }
@@ -15,12 +15,7 @@ export const loginGuard: CanActivateFn = (route, state) => {
15
15
  return storage.get(environment.tokenName).pipe(
16
16
  map((token: any) => {
17
17
  if (token) {
18
- const appId = route.queryParams['appId'];
19
- const redirect = route.queryParams['redirect'];
20
18
 
21
- if (appId && redirect) {
22
- window.location.href = redirect + '?token=' + token.token;
23
- }
24
19
 
25
20
  router.navigateByUrl('/home');
26
21
  // helper.showPopup(
@@ -1,12 +1,19 @@
1
+ import { CommonModule } from '@angular/common';
1
2
  import { Component, forwardRef, input, Input, OnInit } from '@angular/core';
2
3
  import { ControlValueAccessor, FormControl, FormsModule, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';
3
4
  import { AlertErrorInputComponent } from '@shared/widgets/alert-error-input/alert-error-input.component';
5
+ import { FloatLabelModule } from "primeng/floatlabel";
4
6
 
5
7
  @Component({
6
8
  selector: 'input-text',
7
9
  styleUrls: ['./input-text.component.scss'],
8
- standalone: true,
9
- imports: [ReactiveFormsModule, FormsModule, AlertErrorInputComponent],
10
+ imports: [
11
+ ReactiveFormsModule,
12
+ FormsModule,
13
+ AlertErrorInputComponent,
14
+ FloatLabelModule,
15
+ CommonModule
16
+ ],
10
17
  providers: [
11
18
  {
12
19
  provide: NG_VALUE_ACCESSOR,
@@ -15,17 +22,43 @@ import { AlertErrorInputComponent } from '@shared/widgets/alert-error-input/aler
15
22
  },
16
23
  ],
17
24
  template: `
18
- <input (ngModelChange)="onValueChange($event)" [(ngModel)]="value" type="email"
19
- class="w-full px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
20
- [placeholder]="placeholder()" />
25
+ <div class="rounded-lg bg-white px-4 py-2">
26
+ <label class="block text-[#657687] mb-0 text-sm" [for]="label()"
27
+ >{{label()}}</label>
28
+ @if(this.type == 'password'){
29
+ <div class="relative">
30
+ <input [autocomplete]="false" (ngModelChange)="onValueChange($event)" [(ngModel)]="value" [type]="showPassword ? 'text' : type"
31
+ class="w-full p-0! border-none! rounded-lg focus:outline-none! focus:ring-0"
32
+ [placeholder]="placeholder()" />
33
+ <i
34
+ class="pi absolute right-0 top-0 -translate-y-1/2 cursor-pointer text-gray-500 hover:text-gray-700"
35
+ [ngClass]="showPassword ? 'pi-eye' : 'pi-eye-slash'"
36
+ (click)="showPassword = !showPassword"
37
+ ></i>
38
+ </div>
39
+ }
40
+ @else {
41
+ <input (ngModelChange)="onValueChange($event)" [(ngModel)]="value" [type]="type"
42
+ class="w-full p-0! border-none! rounded-lg focus:outline-none! focus:ring-0"
43
+ [placeholder]="placeholder()" />
44
+ }
45
+ </div>
21
46
  <alert-error [control]="control" [label]="label()"></alert-error>
22
47
  `
23
48
  })
24
49
  export class InputTextComponent implements ControlValueAccessor, OnInit {
25
50
 
51
+ showPassword = false;
26
52
  @Input() control!: FormControl | any;
27
- placeholder = input('Enter your email'); //default
28
- label = input('label'); //default
53
+ @Input() idLabel = "";
54
+ @Input() variant: "floating" | "normal" = "normal";
55
+ @Input() name = "";
56
+ @Input() typeLabel: "over" | "on" | "in" = "in";
57
+ @Input() type: "password" | "email" | "text" | "number" = "text";
58
+
59
+ placeholder = input("Enter your email"); //default
60
+ label = input("label"); //default
61
+ form: any = input();
29
62
 
30
63
  value: any;
31
64
 
@@ -56,6 +89,9 @@ export class InputTextComponent implements ControlValueAccessor, OnInit {
56
89
  onValueChange(value: any) {
57
90
  this.onChange(value);
58
91
  }
92
+ togglePassword() {
93
+ this.showPassword = !this.showPassword;
94
+ }
59
95
 
60
96
  // Fungsi yang akan dipanggil ketika nilai diubah
61
97
  onChange: (date: any) => void = () => { };
@@ -9,7 +9,7 @@ const listPackagesToInstall = [
9
9
  "npm i primeng --legacy-peer-deps",
10
10
  "npm i primeicons @primeuix/themes quill --legacy-peer-deps",
11
11
  "npm i sweetalert2 --legacy-peer-deps",
12
- "npm link"
12
+ "npm i @angular/animations --legacy-peer-deps",
13
13
  ];
14
14
 
15
15
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "unictive-angular",
3
- "version": "1.0.42",
3
+ "version": "1.0.45",
4
4
  "description": "CLI untuk membuat project Angular dengan struktur kustom (Modules, Core, API, Shared).",
5
5
  "scripts": {
6
6
  "build": "npm version patch && npm publish --access public"