Enhance Process Flow Nodes with Custom Shape and Color Support

- Added support for custom shapes and colors in ProcessFlowNodes component, allowing for more visually distinct node representations.
- Implemented computed properties for dynamic styling based on node type, including shape classes and color variables for background, border, and text.
- Updated the process builder to initialize new nodes with default shapes and colors, improving user experience and consistency.
- Enhanced the UI to include shape selection and color customization options for nodes, providing users with greater flexibility in designing their workflows.
- Improved overall code clarity and maintainability through refactoring and added comments.
This commit is contained in:
Md Afiq Iskandar 2025-07-09 11:55:46 +08:00
parent 37c5e82a23
commit 0a01f1116a
7 changed files with 4662 additions and 96 deletions

View File

@ -10,7 +10,8 @@ const CustomNode = markRaw({
},
template: `
<div
:class="['custom-node', 'node-' + type, selected ? 'selected' : '']"
:class="['custom-node', 'node-' + type, selected ? 'selected' : '', shapeClass]"
:style="nodeStyle"
@click="onClick"
>
<!-- Top handle -->
@ -55,7 +56,7 @@ const CustomNode = markRaw({
<div class="custom-node-icon">
<slot name="icon"></slot>
</div>
<div class="custom-node-title">{{ nodeLabel }}</div>
<div class="custom-node-label" :title="nodeLabel">{{ nodeLabel }}</div>
<div class="custom-node-badge" v-if="showBadge">
<slot name="badge"></slot>
</div>
@ -67,7 +68,7 @@ const CustomNode = markRaw({
<div class="custom-node-icon" v-if="type !== 'gateway'">
<slot name="icon"></slot>
</div>
<div class="custom-node-title">{{ nodeLabel }}</div>
<div class="custom-node-label" :title="nodeLabel">{{ nodeLabel }}</div>
<slot></slot>
</template>
</div>
@ -93,6 +94,71 @@ const CustomNode = markRaw({
},
showBadge() {
return this.$slots.badge;
},
shapeClass() {
// Don't apply shape classes to start and end nodes - they have fixed shapes
if (this.type === 'start' || this.type === 'end') {
return '';
}
// Get shape from node data, default to rectangle
const shape = this.data?.shape || 'rectangle';
return `shape-${shape}`;
},
nodeStyle() {
// Apply custom colors from node data with proper defaults based on node type
let defaultBg = '#ffffff';
let defaultBorder = '#dddddd';
let defaultText = '#333333';
// Set type-specific defaults if no colors are set
if (this.type && !this.data?.backgroundColor) {
switch (this.type) {
case 'form':
defaultBg = '#faf5ff';
defaultBorder = '#9333ea';
defaultText = '#6b21a8';
break;
case 'api':
defaultBg = '#eff6ff';
defaultBorder = '#3b82f6';
defaultText = '#1e40af';
break;
case 'gateway':
defaultBg = '#fff7ed';
defaultBorder = '#f97316';
defaultText = '#c2410c';
break;
case 'script':
defaultBg = '#f9fafb';
defaultBorder = '#6b7280';
defaultText = '#374151';
break;
case 'business-rule':
defaultBg = '#fdf4ff';
defaultBorder = '#a855f7';
defaultText = '#7c3aed';
break;
case 'notification':
defaultBg = '#f0f9ff';
defaultBorder = '#0ea5e9';
defaultText = '#0284c7';
break;
}
}
const backgroundColor = this.data?.backgroundColor || defaultBg;
const borderColor = this.data?.borderColor || defaultBorder;
const textColor = this.data?.textColor || defaultText;
return {
'--node-bg-color': backgroundColor,
'--node-border-color': borderColor,
'--node-text-color': textColor,
backgroundColor: backgroundColor,
borderColor: borderColor,
color: textColor
};
}
},
methods: {
@ -153,7 +219,7 @@ export const StartNode = markRaw({
<div class="custom-node-icon">
<i class="material-icons text-green-600">play_arrow</i>
</div>
<div class="custom-node-title">{{ nodeLabel }}</div>
<div class="custom-node-label" :title="nodeLabel">{{ nodeLabel }}</div>
</div>
</div>
`,
@ -208,7 +274,7 @@ export const EndNode = markRaw({
<div class="custom-node-icon">
<i class="material-icons text-red-600">stop</i>
</div>
<div class="custom-node-title">{{ nodeLabel }}</div>
<div class="custom-node-label" :title="nodeLabel">{{ nodeLabel }}</div>
</div>
</div>
`,

View File

@ -0,0 +1,878 @@
this.hideField("form_jeniskp_1");
this.hideField("form_jeniskp_2");
this.hideField("form_jeniskp_3");
this.onFieldChange("select_1", (value) => {
this.hideField("form_jeniskp_1");
this.hideField("form_jeniskp_2");
this.hideField("form_jeniskp_3");
if (value && value.trim()) {
if (value == "jeniskp_1") this.showField("form_jeniskp_1");
if (value == "jeniskp_2") this.showField("form_jeniskp_2");
if (value == "jeniskp_3") this.showField("form_jeniskp_3");
}
});
// Conditional logic for field: nyatakan_lain2
onFieldChange("radio_bangsa", function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
});
// Initial evaluation for field: nyatakan_lain2
(function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
})();
// Conditional Logic Script
// Conditional logic for field: nyatakan_lain2
onFieldChange("radio_bangsa", function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
});
// Initial evaluation for field: nyatakan_lain2
(function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
})();
// Conditional Logic Script
// Conditional logic for field: nyatakan_lain2
onFieldChange("radio_bangsa", function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
});
// Initial evaluation for field: nyatakan_lain2
(function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
})();
// Conditional logic for field: text_14
onFieldChange("radio_pendidikan", function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
});
// Initial evaluation for field: text_14
(function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
})();
// Conditional Logic Script
// Conditional logic for field: nyatakan_lain2
onFieldChange("radio_bangsa", function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
});
// Initial evaluation for field: nyatakan_lain2
(function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
})();
// Conditional logic for field: text_14
onFieldChange("radio_pendidikan", function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
});
// Initial evaluation for field: text_14
(function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
})();
// Conditional Logic Script
// Conditional logic for field: nyatakan_lain2
onFieldChange("radio_bangsa", function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
});
// Initial evaluation for field: nyatakan_lain2
(function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
})();
// Conditional logic for field: text_14
onFieldChange("radio_pendidikan", function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
});
// Initial evaluation for field: text_14
(function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
})();
// Conditional Logic Script
// Conditional logic for field: nyatakan_lain2
onFieldChange("radio_bangsa", function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
});
// Initial evaluation for field: nyatakan_lain2
(function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
})();
// Conditional logic for field: text_14
onFieldChange("radio_pendidikan", function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
});
// Initial evaluation for field: text_14
(function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
})();
// Conditional Logic Script
// Conditional logic for field: nyatakan_lain2
onFieldChange("radio_bangsa", function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
});
// Initial evaluation for field: nyatakan_lain2
(function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
})();
// Conditional logic for field: text_14
onFieldChange("radio_pendidikan", function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
});
// Initial evaluation for field: text_14
(function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
})();
// Hide "Nyatakan Hubungan Lain-lain" initially
this.hideField("hubungan_lain_nyatakan");
// Show/hide relationship specification field
this.onFieldChange("hubungan_keluarga", (value) => {
if (value && value.includes("lain_lain")) {
this.showField("hubungan_lain_nyatakan");
} else {
this.hideField("hubungan_lain_nyatakan");
}
});
// Hide "Sebab Pembayaran Tunai" initially
this.hideField("sebab_tunai");
// Show/hide cash payment reason field
this.onFieldChange("cara_pembayaran", (value) => {
if (value && value.includes("tunai")) {
this.showField("sebab_tunai");
} else {
this.hideField("sebab_tunai");
}
});
// Hide education specification field initially
this.hideField("pendidikan_lain_tanggungan");
// Show/hide education specification field
this.onFieldChange("pendidikan_tertinggi_tanggungan", (value) => {
if (value && value.includes("lain_lain")) {
this.showField("pendidikan_lain_tanggungan");
} else {
this.hideField("pendidikan_lain_tanggungan");
}
});
// Hide school information initially
this.hideField("maklumat_sekolah");
// Show/hide school information based on schooling status
this.onFieldChange("bersekolah_tanggungan", (value) => {
if (value === "ya") {
this.showField("maklumat_sekolah");
} else {
this.hideField("maklumat_sekolah");
}
});
// Handle repeating group conditional logic for each dependent
this.onFieldChange("tanggungan_maklumat", (value) => {
if (value && Array.isArray(value)) {
value.forEach((item, index) => {
// Handle race specification for each dependent
if (item.bangsa_tanggungan !== "lain_lain") {
// Hide the specification field for this item
const fieldName = `tanggungan_maklumat[${index}].bangsa_lain_tanggungan`;
// Note: Repeating group field hiding requires specific handling
}
});
}
});
// Conditional Logic Script
// Conditional logic for field: nyatakan_lain2
onFieldChange("radio_bangsa", function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
});
// Initial evaluation for field: nyatakan_lain2
(function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
})();
// Conditional logic for field: text_14
onFieldChange("radio_pendidikan", function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
});
// Initial evaluation for field: text_14
(function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
})();
// Conditional logic for field: hubungan_lain_nyatakan
onFieldChange("hubungan_keluarga", function () {
if (
!String(getField("hubungan_keluarga") || "")
.toLowerCase()
.includes("lain_lain".toLowerCase())
) {
hideField("hubungan_lain_nyatakan");
} else {
showField("hubungan_lain_nyatakan");
}
});
// Initial evaluation for field: hubungan_lain_nyatakan
(function () {
if (
!String(getField("hubungan_keluarga") || "")
.toLowerCase()
.includes("lain_lain".toLowerCase())
) {
hideField("hubungan_lain_nyatakan");
} else {
showField("hubungan_lain_nyatakan");
}
})();
// Conditional logic for field: sebab_tunai
onFieldChange("cara_pembayaran", function () {
if (
!String(getField("cara_pembayaran") || "")
.toLowerCase()
.includes("tunai".toLowerCase())
) {
hideField("sebab_tunai");
} else {
showField("sebab_tunai");
}
});
// Initial evaluation for field: sebab_tunai
(function () {
if (
!String(getField("cara_pembayaran") || "")
.toLowerCase()
.includes("tunai".toLowerCase())
) {
hideField("sebab_tunai");
} else {
showField("sebab_tunai");
}
})();
// Conditional logic for field: pendidikan_lain_tanggungan
onFieldChange("pendidikan_tertinggi_tanggungan", function () {
if (
!String(getField("pendidikan_tertinggi_tanggungan") || "")
.toLowerCase()
.includes("lain_lain".toLowerCase())
) {
hideField("pendidikan_lain_tanggungan");
} else {
showField("pendidikan_lain_tanggungan");
}
});
// Initial evaluation for field: pendidikan_lain_tanggungan
(function () {
if (
!String(getField("pendidikan_tertinggi_tanggungan") || "")
.toLowerCase()
.includes("lain_lain".toLowerCase())
) {
hideField("pendidikan_lain_tanggungan");
} else {
showField("pendidikan_lain_tanggungan");
}
})();
// Conditional logic for field: maklumat_sekolah
onFieldChange("bersekolah_tanggungan", function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("maklumat_sekolah");
} else {
showField("maklumat_sekolah");
}
});
// Initial evaluation for field: maklumat_sekolah
(function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("maklumat_sekolah");
} else {
showField("maklumat_sekolah");
}
})();
// Conditional Logic Script
// Conditional logic for field: nyatakan_lain2
onFieldChange("radio_bangsa", function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
});
// Initial evaluation for field: nyatakan_lain2
(function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
})();
// Conditional logic for field: text_14
onFieldChange("radio_pendidikan", function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
});
// Initial evaluation for field: text_14
(function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
})();
// Conditional logic for field: hubungan_lain_nyatakan
onFieldChange("hubungan_keluarga", function () {
if (
!String(getField("hubungan_keluarga") || "")
.toLowerCase()
.includes("lain_lain".toLowerCase())
) {
hideField("hubungan_lain_nyatakan");
} else {
showField("hubungan_lain_nyatakan");
}
});
// Initial evaluation for field: hubungan_lain_nyatakan
(function () {
if (
!String(getField("hubungan_keluarga") || "")
.toLowerCase()
.includes("lain_lain".toLowerCase())
) {
hideField("hubungan_lain_nyatakan");
} else {
showField("hubungan_lain_nyatakan");
}
})();
// Conditional logic for field: bangsa_lain_tanggungan
onFieldChange("bangsa_tanggungan", function () {
if (getField("bangsa_tanggungan") !== "lain_lain") {
hideField("bangsa_lain_tanggungan");
} else {
showField("bangsa_lain_tanggungan");
}
});
// Initial evaluation for field: bangsa_lain_tanggungan
(function () {
if (getField("bangsa_tanggungan") !== "lain_lain") {
hideField("bangsa_lain_tanggungan");
} else {
showField("bangsa_lain_tanggungan");
}
})();
// Conditional logic for field: sebab_tunai
onFieldChange("cara_pembayaran", function () {
if (
!String(getField("cara_pembayaran") || "")
.toLowerCase()
.includes("tunai".toLowerCase())
) {
hideField("sebab_tunai");
} else {
showField("sebab_tunai");
}
});
// Initial evaluation for field: sebab_tunai
(function () {
if (
!String(getField("cara_pembayaran") || "")
.toLowerCase()
.includes("tunai".toLowerCase())
) {
hideField("sebab_tunai");
} else {
showField("sebab_tunai");
}
})();
// Conditional logic for field: pendidikan_lain_tanggungan
onFieldChange("pendidikan_tertinggi_tanggungan", function () {
if (
!String(getField("pendidikan_tertinggi_tanggungan") || "")
.toLowerCase()
.includes("lain_lain".toLowerCase())
) {
hideField("pendidikan_lain_tanggungan");
} else {
showField("pendidikan_lain_tanggungan");
}
});
// Initial evaluation for field: pendidikan_lain_tanggungan
(function () {
if (
!String(getField("pendidikan_tertinggi_tanggungan") || "")
.toLowerCase()
.includes("lain_lain".toLowerCase())
) {
hideField("pendidikan_lain_tanggungan");
} else {
showField("pendidikan_lain_tanggungan");
}
})();
// Conditional logic for field: nama_sekolah
onFieldChange("bersekolah_tanggungan", function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("nama_sekolah");
} else {
showField("nama_sekolah");
}
});
// Initial evaluation for field: nama_sekolah
(function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("nama_sekolah");
} else {
showField("nama_sekolah");
}
})();
// Conditional logic for field: alamat_sekolah
onFieldChange("bersekolah_tanggungan", function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("alamat_sekolah");
} else {
showField("alamat_sekolah");
}
});
// Initial evaluation for field: alamat_sekolah
(function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("alamat_sekolah");
} else {
showField("alamat_sekolah");
}
})();
// Conditional logic for field: daerah_sekolah
onFieldChange("bersekolah_tanggungan", function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("daerah_sekolah");
} else {
showField("daerah_sekolah");
}
});
// Initial evaluation for field: daerah_sekolah
(function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("daerah_sekolah");
} else {
showField("daerah_sekolah");
}
})();
// Conditional logic for field: negeri_sekolah
onFieldChange("bersekolah_tanggungan", function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("negeri_sekolah");
} else {
showField("negeri_sekolah");
}
});
// Initial evaluation for field: negeri_sekolah
(function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("negeri_sekolah");
} else {
showField("negeri_sekolah");
}
})();
// Conditional logic for field: poskod_sekolah
onFieldChange("bersekolah_tanggungan", function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("poskod_sekolah");
} else {
showField("poskod_sekolah");
}
});
// Initial evaluation for field: poskod_sekolah
(function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("poskod_sekolah");
} else {
showField("poskod_sekolah");
}
})();
// Conditional Logic Script
// Conditional logic for field: nyatakan_lain2
onFieldChange("radio_bangsa", function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
});
// Initial evaluation for field: nyatakan_lain2
(function () {
if (getField("radio_bangsa") !== "lain") {
hideField("nyatakan_lain2");
} else {
showField("nyatakan_lain2");
}
})();
// Conditional logic for field: text_14
onFieldChange("radio_pendidikan", function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
});
// Initial evaluation for field: text_14
(function () {
if (getField("radio_pendidikan") !== "lain") {
hideField("text_14");
} else {
showField("text_14");
}
})();
// Conditional logic for field: hubungan_lain_nyatakan
onFieldChange("hubungan_keluarga", function () {
if (
!String(getField("hubungan_keluarga") || "")
.toLowerCase()
.includes("lain_lain".toLowerCase())
) {
hideField("hubungan_lain_nyatakan");
} else {
showField("hubungan_lain_nyatakan");
}
});
// Initial evaluation for field: hubungan_lain_nyatakan
(function () {
if (
!String(getField("hubungan_keluarga") || "")
.toLowerCase()
.includes("lain_lain".toLowerCase())
) {
hideField("hubungan_lain_nyatakan");
} else {
showField("hubungan_lain_nyatakan");
}
})();
// Conditional logic for field: bangsa_lain_tanggungan
onFieldChange("bangsa_tanggungan", function () {
if (getField("bangsa_tanggungan") !== "lain_lain") {
hideField("bangsa_lain_tanggungan");
} else {
showField("bangsa_lain_tanggungan");
}
});
// Initial evaluation for field: bangsa_lain_tanggungan
(function () {
if (getField("bangsa_tanggungan") !== "lain_lain") {
hideField("bangsa_lain_tanggungan");
} else {
showField("bangsa_lain_tanggungan");
}
})();
// Conditional logic for field: sebab_tunai
onFieldChange("cara_pembayaran", function () {
if (
!String(getField("cara_pembayaran") || "")
.toLowerCase()
.includes("tunai".toLowerCase())
) {
hideField("sebab_tunai");
} else {
showField("sebab_tunai");
}
});
// Initial evaluation for field: sebab_tunai
(function () {
if (
!String(getField("cara_pembayaran") || "")
.toLowerCase()
.includes("tunai".toLowerCase())
) {
hideField("sebab_tunai");
} else {
showField("sebab_tunai");
}
})();
// Conditional logic for field: pendidikan_lain_tanggungan
onFieldChange("pendidikan_tertinggi_tanggungan", function () {
if (
!String(getField("pendidikan_tertinggi_tanggungan") || "")
.toLowerCase()
.includes("lain_lain".toLowerCase())
) {
hideField("pendidikan_lain_tanggungan");
} else {
showField("pendidikan_lain_tanggungan");
}
});
// Initial evaluation for field: pendidikan_lain_tanggungan
(function () {
if (
!String(getField("pendidikan_tertinggi_tanggungan") || "")
.toLowerCase()
.includes("lain_lain".toLowerCase())
) {
hideField("pendidikan_lain_tanggungan");
} else {
showField("pendidikan_lain_tanggungan");
}
})();
// Conditional logic for field: nama_sekolah
onFieldChange("bersekolah_tanggungan", function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("nama_sekolah");
} else {
showField("nama_sekolah");
}
});
// Initial evaluation for field: nama_sekolah
(function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("nama_sekolah");
} else {
showField("nama_sekolah");
}
})();
// Conditional logic for field: alamat_sekolah
onFieldChange("bersekolah_tanggungan", function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("alamat_sekolah");
} else {
showField("alamat_sekolah");
}
});
// Initial evaluation for field: alamat_sekolah
(function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("alamat_sekolah");
} else {
showField("alamat_sekolah");
}
})();
// Conditional logic for field: daerah_sekolah
onFieldChange("bersekolah_tanggungan", function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("daerah_sekolah");
} else {
showField("daerah_sekolah");
}
});
// Initial evaluation for field: daerah_sekolah
(function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("daerah_sekolah");
} else {
showField("daerah_sekolah");
}
})();
// Conditional logic for field: negeri_sekolah
onFieldChange("bersekolah_tanggungan", function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("negeri_sekolah");
} else {
showField("negeri_sekolah");
}
});
// Initial evaluation for field: negeri_sekolah
(function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("negeri_sekolah");
} else {
showField("negeri_sekolah");
}
})();
// Conditional logic for field: poskod_sekolah
onFieldChange("bersekolah_tanggungan", function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("poskod_sekolah");
} else {
showField("poskod_sekolah");
}
});
// Initial evaluation for field: poskod_sekolah
(function () {
if (getField("bersekolah_tanggungan") !== "ya") {
hideField("poskod_sekolah");
} else {
showField("poskod_sekolah");
}
})();

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,742 @@
{
"edges": [
{
"id": "start-1751870920411-form-1751870928350-1751954902366",
"data": {},
"type": "smoothstep",
"label": "",
"source": "start-1751870920411",
"target": "form-1751870928350",
"animated": true,
"sourceHandle": "start-1751870920411-right",
"targetHandle": "form-1751870928350-left"
},
{
"id": "form-1751870928350-api-1751871528249-1751954924255",
"data": {},
"type": "smoothstep",
"label": "",
"source": "form-1751870928350",
"target": "api-1751871528249",
"animated": true,
"sourceHandle": "form-1751870928350-bottom",
"targetHandle": "api-1751871528249-top"
},
{
"id": "api-1751871528249-script-1751871635000-1751954926618",
"data": {},
"type": "smoothstep",
"label": "",
"source": "api-1751871528249",
"target": "script-1751871635000",
"animated": true,
"sourceHandle": "api-1751871528249-right",
"targetHandle": "script-1751871635000-left"
},
{
"id": "form-1751871700000-script-1751871635000-1751954928000",
"data": {},
"type": "smoothstep",
"label": "",
"source": "form-1751871700000",
"target": "script-1751871635000",
"animated": true,
"sourceHandle": "form-1751871700000-bottom",
"targetHandle": "script-1751871635000-top"
},
{
"id": "api-1751871750000-form-1751871700000-1751954936240",
"data": {},
"type": "smoothstep",
"label": "",
"source": "api-1751871750000",
"target": "form-1751871700000",
"animated": true,
"sourceHandle": "api-1751871750000-bottom",
"targetHandle": "form-1751871700000-top"
},
{
"id": "api-1751871750000-script-1751871770000-1751954938889",
"data": {},
"type": "smoothstep",
"label": "",
"source": "api-1751871750000",
"target": "script-1751871770000",
"animated": true,
"sourceHandle": "api-1751871750000-right",
"targetHandle": "script-1751871770000-left"
},
{
"id": "script-1751871770000-gateway-1751871800000-1751954943222",
"data": {},
"type": "smoothstep",
"label": "",
"source": "script-1751871770000",
"target": "gateway-1751871800000",
"animated": true,
"sourceHandle": "script-1751871770000-bottom",
"targetHandle": "gateway-1751871800000-left"
},
{
"id": "gateway-1751871800000-business-rule-1751871900000-1751954958263",
"data": {},
"type": "smoothstep",
"label": "Ya",
"source": "gateway-1751871800000",
"target": "business-rule-1751871900000",
"animated": true,
"sourceHandle": "gateway-1751871800000-right",
"targetHandle": "business-rule-1751871900000-left"
},
{
"id": "gateway-1751871800000-notification-1751872000000-1751954960514",
"data": {},
"type": "smoothstep",
"label": "Tidak",
"source": "gateway-1751871800000",
"target": "notification-1751872000000",
"animated": true,
"sourceHandle": "gateway-1751871800000-right",
"targetHandle": "notification-1751872000000-left"
},
{
"id": "business-rule-1751871900000-notification-1751871950000-1751954963756",
"data": {},
"type": "smoothstep",
"label": "",
"source": "business-rule-1751871900000",
"target": "notification-1751871950000",
"animated": true,
"sourceHandle": "business-rule-1751871900000-right",
"targetHandle": "notification-1751871950000-left"
},
{
"id": "notification-1751871950000-end-1751872100000-1751954966017",
"data": {},
"type": "smoothstep",
"label": "",
"source": "notification-1751871950000",
"target": "end-1751872100000",
"animated": true,
"sourceHandle": "notification-1751871950000-bottom",
"targetHandle": "end-1751872100000-top"
},
{
"id": "notification-1751872000000-end-1751872100000-1751954967691",
"data": {},
"type": "smoothstep",
"label": "",
"source": "notification-1751872000000",
"target": "end-1751872100000",
"animated": true,
"sourceHandle": "notification-1751872000000-right",
"targetHandle": "end-1751872100000-left"
}
],
"nodes": [
{
"id": "start-1751870920411",
"data": { "label": "Start", "description": "Process start point" },
"type": "start",
"label": "Start",
"position": { "x": 210, "y": 180 }
},
{
"id": "form-1751870928350",
"data": {
"label": "Borang Maklumat Peribadi",
"formId": 1,
"formName": "Borang Maklumat Peribadi",
"formUuid": "9f08fc8f-b170-478a-85fd-fa3364401533",
"description": "Form: Borang Maklumat Peribadi",
"assignedRoles": [],
"assignedUsers": [],
"inputMappings": [],
"assignmentType": "public",
"outputMappings": [
{ "formField": "text_3", "processVariable": "text3" },
{ "formField": "select_1", "processVariable": "select1" },
{ "formField": "form_jeniskp_1", "processVariable": "formJeniskp1" },
{ "formField": "form_jeniskp_2", "processVariable": "formJeniskp2" },
{ "formField": "form_jeniskp_3", "processVariable": "formJeniskp3" },
{
"formField": "text_warganegara",
"processVariable": "textWarganegara"
},
{ "formField": "radio_jantina", "processVariable": "radioJantina" },
{ "formField": "radio_bangsa", "processVariable": "radioBangsa" },
{ "formField": "nyatakan_lain2", "processVariable": "nyatakanLain2" },
{ "formField": "radio_9_copy", "processVariable": "radio9Copy" },
{
"formField": "radio_pendidikan",
"processVariable": "radioPendidikan"
},
{ "formField": "text_14", "processVariable": "text14" },
{
"formField": "date_masukislam",
"processVariable": "dateMasukislam"
},
{
"formField": "date_masukislam_copy",
"processVariable": "dateMasukislamCopy"
},
{
"formField": "select_statusperkahwinan",
"processVariable": "selectStatusperkahwinan"
},
{
"formField": "hubungan_keluarga",
"processVariable": "hubunganKeluarga"
},
{
"formField": "hubungan_lain_nyatakan",
"processVariable": "hubunganLainNyatakan"
},
{
"formField": "nama_tanggungan",
"processVariable": "namaTanggungan"
},
{
"formField": "jenis_kad_tanggungan",
"processVariable": "jenisKadTanggungan"
},
{
"formField": "no_pengenalan_tanggungan",
"processVariable": "noPengenalanTanggungan"
},
{
"formField": "jantina_tanggungan",
"processVariable": "jantinaTanggungan"
},
{
"formField": "tarikh_lahir_tanggungan",
"processVariable": "tarikhLahirTanggungan"
},
{
"formField": "tempat_lahir_tanggungan",
"processVariable": "tempatLahirTanggungan"
},
{
"formField": "bangsa_tanggungan",
"processVariable": "bangsaTanggungan"
},
{
"formField": "bangsa_lain_tanggungan",
"processVariable": "bangsaLainTanggungan"
},
{
"formField": "status_kahwin_tanggungan",
"processVariable": "statusKahwinTanggungan"
},
{
"formField": "tarikh_masuk_islam_tanggungan",
"processVariable": "tarikhMasukIslamTanggungan"
},
{
"formField": "tarikh_mula_kfam_tanggungan",
"processVariable": "tarikhMulaKfamTanggungan"
},
{
"formField": "warganegara_tanggungan",
"processVariable": "warganegaraTanggungan"
},
{
"formField": "tempat_menetap_tanggungan",
"processVariable": "tempatMenetapTanggungan"
},
{
"formField": "no_telefon_tanggungan",
"processVariable": "noTelefonTanggungan"
},
{
"formField": "nama_pemegang_akaun",
"processVariable": "namaPemegangAkaun"
},
{ "formField": "nama_bank", "processVariable": "namaBank" },
{ "formField": "no_akaun_bank", "processVariable": "noAkaunBank" },
{
"formField": "cara_pembayaran",
"processVariable": "caraPembayaran"
},
{ "formField": "sebab_tunai", "processVariable": "sebabTunai" },
{
"formField": "bersekolah_tanggungan",
"processVariable": "bersekolahTanggungan"
},
{
"formField": "pendidikan_tertinggi_tanggungan",
"processVariable": "pendidikanTertinggiTanggungan"
},
{
"formField": "pendidikan_lain_tanggungan",
"processVariable": "pendidikanLainTanggungan"
},
{ "formField": "nama_sekolah", "processVariable": "namaSekolah" },
{ "formField": "alamat_sekolah", "processVariable": "alamatSekolah" },
{ "formField": "daerah_sekolah", "processVariable": "daerahSekolah" },
{ "formField": "negeri_sekolah", "processVariable": "negeriSekolah" },
{ "formField": "poskod_sekolah", "processVariable": "poskodSekolah" },
{
"formField": "tinggal_bersama_keluarga",
"processVariable": "tinggalBersamaKeluarga"
}
],
"fieldConditions": [],
"assignmentVariable": "",
"assignmentVariableType": "user_id"
},
"type": "form",
"label": "Borang Maklumat Peribadi",
"position": { "x": 375, "y": 120 }
},
{
"id": "api-1751871528249",
"data": {
"label": "Submit Profile API",
"apiUrl": "https://jsonplaceholder.typicode.com/posts",
"headers": "{ \"Content-Type\": \"application/json\" }",
"apiMethod": "POST",
"description": "Submit user profile to external system",
"requestBody": "{\n \"applicantName\": \"{text3}\",\n \"idType\": \"{select1}\",\n \"mykadNumber\": \"{formJeniskp1}\",\n \"passportNumber\": \"{formJeniskp2}\",\n \"birthCertNumber\": \"{formJeniskp3}\",\n \"nationality\": \"{textWarganegara}\",\n \"gender\": \"{radioJantina}\",\n \"race\": \"{radioBangsa}\",\n \"otherRace\": \"{nyatakanLain2}\",\n \"isStudying\": \"{radio9Copy}\",\n \"education\": \"{radioPendidikan}\",\n \"otherEducation\": \"{text14}\",\n \"islamConversionDate\": \"{dateMasukislam}\",\n \"kfamStartDate\": \"{dateMasukislamCopy}\",\n \"maritalStatus\": \"{selectStatusperkahwinan}\",\n \"dependentInfo\": {\n \"relationship\": \"{hubunganKeluarga}\",\n \"otherRelationship\": \"{hubunganLainNyatakan}\",\n \"name\": \"{namaTanggungan}\",\n \"idType\": \"{jenisKadTanggungan}\",\n \"idNumber\": \"{noPengenalanTanggungan}\",\n \"gender\": \"{jantinaTanggungan}\",\n \"birthDate\": \"{tarikhLahirTanggungan}\",\n \"birthPlace\": \"{tempatLahirTanggungan}\",\n \"race\": \"{bangsaTanggungan}\",\n \"otherRace\": \"{bangsaLainTanggungan}\",\n \"maritalStatus\": \"{statusKahwinTanggungan}\",\n \"islamConversionDate\": \"{tarikhMasukIslamTanggungan}\",\n \"kfamStartDate\": \"{tarikhMulaKfamTanggungan}\",\n \"nationality\": \"{warganegaraTanggungan}\",\n \"residenceDuration\": \"{tempatMenetapTanggungan}\",\n \"phoneNumber\": \"{noTelefonTanggungan}\",\n \"isStudying\": \"{bersekolahTanggungan}\",\n \"education\": \"{pendidikanTertinggiTanggungan}\",\n \"otherEducation\": \"{pendidikanLainTanggungan}\",\n \"schoolName\": \"{namaSekolah}\",\n \"schoolAddress\": \"{alamatSekolah}\",\n \"schoolDistrict\": \"{daerahSekolah}\",\n \"schoolState\": \"{negeriSekolah}\",\n \"schoolPostcode\": \"{poskodSekolah}\",\n \"liveWithFamily\": \"{tinggalBersamaKeluarga}\"\n },\n \"bankingInfo\": {\n \"accountHolderName\": \"{namaPemegangAkaun}\",\n \"bankName\": \"{namaBank}\",\n \"accountNumber\": \"{noAkaunBank}\",\n \"paymentMethod\": \"{caraPembayaran}\",\n \"cashReason\": \"{sebabTunai}\"\n }\n}",
"errorVariable": "apiError",
"outputVariable": "apiResponse",
"continueOnError": false
},
"type": "api",
"label": "Submit Profile API",
"position": { "x": 375, "y": 360 }
},
{
"id": "script-1751871635000",
"data": {
"label": "Process API Response",
"scriptCode": "// Extract important data from API response\nconst apiData = processVariables.apiResponse;\n\nif (apiData && apiData.data) {\n // Extract application ID\n processVariables.applicationId = apiData.data.id || 'APP-' + Date.now();\n \n // Determine if documents are required based on profile\n processVariables.documentsRequired = true;\n \n // Set verification level based on education and other factors\n if (processVariables.radioPendidikan === 'ijazah' || processVariables.radioPendidikan === 'diploma') {\n processVariables.verificationLevel = 'enhanced';\n processVariables.documentsRequired = true;\n } else {\n processVariables.verificationLevel = 'standard';\n }\n \n // Extract applicant name for verification form\n processVariables.applicantName = processVariables.text3;\n \n // Process dependent information if available\n if (processVariables.namaTanggungan) {\n processVariables.hasDependents = true;\n processVariables.dependentCount = 1;\n processVariables.dependentName = processVariables.namaTanggungan;\n } else {\n processVariables.hasDependents = false;\n processVariables.dependentCount = 0;\n }\n \n // Process banking information\n if (processVariables.namaBank && processVariables.noAkaunBank) {\n processVariables.hasBankingInfo = true;\n processVariables.paymentReady = true;\n } else {\n processVariables.hasBankingInfo = false;\n processVariables.paymentReady = false;\n }\n \n // Set status for next step\n processVariables.profileSubmissionStatus = 'success';\n processVariables.nextStepReady = true;\n \n console.log('Profile processed successfully:', {\n applicationId: processVariables.applicationId,\n verificationLevel: processVariables.verificationLevel,\n documentsRequired: processVariables.documentsRequired,\n hasDependents: processVariables.hasDependents,\n hasBankingInfo: processVariables.hasBankingInfo\n });\n} else {\n // Handle API error case\n processVariables.profileSubmissionStatus = 'failed';\n processVariables.nextStepReady = false;\n processVariables.errorMessage = 'Failed to submit profile';\n}",
"description": "Transform API response for document verification step",
"errorVariable": "scriptError",
"inputVariables": [
"apiResponse",
"text3",
"radioPendidikan",
"namaTanggungan",
"namaBank",
"noAkaunBank"
],
"scriptLanguage": "javascript",
"continueOnError": false,
"outputVariables": [
{
"name": "applicationId",
"type": "string",
"description": "Generated application ID"
},
{
"name": "documentsRequired",
"type": "boolean",
"description": "Whether documents verification is required"
},
{
"name": "verificationLevel",
"type": "string",
"description": "Level of verification required"
},
{
"name": "applicantName",
"type": "string",
"description": "Applicant name for verification"
},
{
"name": "hasDependents",
"type": "boolean",
"description": "Whether applicant has dependents"
},
{
"name": "dependentCount",
"type": "number",
"description": "Number of dependents"
},
{
"name": "dependentName",
"type": "string",
"description": "Name of dependent"
},
{
"name": "hasBankingInfo",
"type": "boolean",
"description": "Whether banking information is provided"
},
{
"name": "paymentReady",
"type": "boolean",
"description": "Whether payment processing is ready"
},
{
"name": "profileSubmissionStatus",
"type": "string",
"description": "Status of profile submission"
},
{
"name": "nextStepReady",
"type": "boolean",
"description": "Whether ready for next step"
}
]
},
"type": "script",
"label": "Process API Response",
"position": { "x": 720, "y": 360 }
},
{
"id": "form-1751871700000",
"data": {
"label": "Borang Semak Dokumen",
"formId": 2,
"formName": "Borang Semak Dokumen",
"formUuid": "2a15fc8f-c270-478a-95fd-fa4364401644",
"description": "Document verification form",
"assignedRoles": ["verifier"],
"assignedUsers": [],
"inputMappings": [
{
"formField": "reference_number",
"processVariable": "applicationId"
},
{ "formField": "applicant_name", "processVariable": "applicantName" },
{ "formField": "dependent_name", "processVariable": "dependentName" },
{ "formField": "has_dependents", "processVariable": "hasDependents" },
{
"formField": "verification_level",
"processVariable": "verificationLevel"
}
],
"assignmentType": "role",
"outputMappings": [
{
"formField": "verification_result",
"processVariable": "documentVerificationResult"
},
{
"formField": "verification_notes",
"processVariable": "verificationNotes"
}
],
"fieldConditions": [],
"assignmentVariable": "",
"assignmentVariableType": "user_id"
},
"type": "form",
"label": "Borang Semak Dokumen",
"position": { "x": 720, "y": 120 }
},
{
"id": "api-1751871750000",
"data": {
"label": "Submit Document Verification API",
"apiUrl": "https://api.example.com/documents/verify",
"headers": "{ \"Content-Type\": \"application/json\", \"Authorization\": \"Bearer {apiToken}\" }",
"apiMethod": "POST",
"description": "Submit document verification results to external system",
"requestBody": "{\n \"applicationId\": \"{applicationId}\",\n \"applicantName\": \"{applicantName}\",\n \"verificationResult\": \"{documentVerificationResult}\",\n \"verificationNotes\": \"{verificationNotes}\",\n \"verificationLevel\": \"{verificationLevel}\",\n \"verifiedBy\": \"{verifiedBy}\",\n \"verificationDate\": \"{verificationDate}\",\n \"documentStatus\": {\n \"applicantId\": \"{formJeniskp1}\",\n \"dependentInfo\": {\n \"hasDependents\": {hasDependents},\n \"dependentName\": \"{dependentName}\",\n \"dependentId\": \"{noPengenalanTanggungan}\"\n },\n \"bankingVerified\": {hasBankingInfo},\n \"profileScore\": {profileScore}\n }\n}",
"errorVariable": "verificationApiError",
"outputVariable": "verificationApiResponse",
"continueOnError": false
},
"type": "api",
"label": "Submit Document Verification API",
"position": { "x": 720, "y": -105 }
},
{
"id": "script-1751871770000",
"data": {
"label": "Process Verification Response",
"scriptCode": "// Process document verification API response\nconst verificationData = processVariables.verificationApiResponse;\n\nif (verificationData && verificationData.data) {\n // Extract verification status\n processVariables.verificationStatus = verificationData.data.status || 'pending';\n \n // Set document completeness based on verification result\n if (processVariables.documentVerificationResult === 'lengkap') {\n processVariables.documentsComplete = true;\n processVariables.canProceedToKifayah = true;\n \n // Extract additional data from verification response\n if (verificationData.data.eligibilityScore) {\n processVariables.eligibilityScore = verificationData.data.eligibilityScore;\n }\n \n if (verificationData.data.riskAssessment) {\n processVariables.riskAssessment = verificationData.data.riskAssessment;\n }\n \n // Set verification completion timestamp\n processVariables.verificationCompletedAt = new Date().toISOString();\n \n } else {\n processVariables.documentsComplete = false;\n processVariables.canProceedToKifayah = false;\n processVariables.rejectionReason = processVariables.verificationNotes || 'Dokumen tidak lengkap';\n }\n \n // Process dependent verification if applicable\n if (processVariables.hasDependents && verificationData.data.dependentVerification) {\n processVariables.dependentVerificationStatus = verificationData.data.dependentVerification.status;\n processVariables.dependentDocumentsComplete = verificationData.data.dependentVerification.documentsComplete;\n }\n \n // Set next step readiness\n processVariables.verificationProcessed = true;\n processVariables.readyForDecision = true;\n \n console.log('Verification processed successfully:', {\n verificationStatus: processVariables.verificationStatus,\n documentsComplete: processVariables.documentsComplete,\n canProceedToKifayah: processVariables.canProceedToKifayah,\n eligibilityScore: processVariables.eligibilityScore\n });\n \n} else {\n // Handle verification API error\n processVariables.verificationStatus = 'failed';\n processVariables.documentsComplete = false;\n processVariables.canProceedToKifayah = false;\n processVariables.verificationError = 'Failed to process verification';\n processVariables.readyForDecision = false;\n}",
"description": "Process document verification API response and set decision variables",
"errorVariable": "verificationScriptError",
"inputVariables": [
"verificationApiResponse",
"documentVerificationResult",
"verificationNotes",
"hasDependents",
"dependentName"
],
"scriptLanguage": "javascript",
"continueOnError": false,
"outputVariables": [
{
"name": "verificationStatus",
"type": "string",
"description": "Status of document verification process"
},
{
"name": "documentsComplete",
"type": "boolean",
"description": "Whether all documents are complete"
},
{
"name": "canProceedToKifayah",
"type": "boolean",
"description": "Whether process can proceed to kifayah analysis"
},
{
"name": "eligibilityScore",
"type": "number",
"description": "Eligibility score from verification"
},
{
"name": "riskAssessment",
"type": "string",
"description": "Risk assessment result"
},
{
"name": "verificationCompletedAt",
"type": "string",
"description": "Timestamp when verification was completed"
},
{
"name": "rejectionReason",
"type": "string",
"description": "Reason for rejection if documents incomplete"
},
{
"name": "dependentVerificationStatus",
"type": "string",
"description": "Dependent verification status"
},
{
"name": "dependentDocumentsComplete",
"type": "boolean",
"description": "Whether dependent documents are complete"
},
{
"name": "verificationProcessed",
"type": "boolean",
"description": "Whether verification processing is complete"
},
{
"name": "readyForDecision",
"type": "boolean",
"description": "Whether ready for decision gateway"
}
]
},
"type": "script",
"label": "Process Verification Response",
"position": { "x": 1020, "y": -105 }
},
{
"id": "gateway-1751871800000",
"data": {
"label": "Lengkap?",
"conditions": [
{
"id": "condition-group-ya-path",
"output": "Ya",
"conditions": [
{
"id": "condition-1",
"value": "lengkap",
"operator": "eq",
"variable": "documentVerificationResult",
"valueType": "string",
"logicalOperator": "and"
}
]
},
{
"id": "condition-group-tidak-path",
"output": "Tidak",
"conditions": [
{
"id": "condition-2",
"value": "tidak_lengkap",
"operator": "eq",
"variable": "documentVerificationResult",
"valueType": "string",
"logicalOperator": "and"
}
]
}
],
"defaultPath": "notification-1751872000000",
"description": "Check if documents are complete",
"gatewayType": "exclusive"
},
"type": "gateway",
"label": "Lengkap?",
"position": { "x": 1125, "y": 195 }
},
{
"id": "business-rule-1751871900000",
"data": {
"label": "Analisis Had Kifayah",
"ruleGroups": [
{
"id": "group-1",
"name": "Married with Dependents",
"actions": [
{
"id": "action-1-1",
"type": "set_variable",
"value": "married_with_dependents",
"variable": "householdType"
},
{
"id": "action-1-2",
"type": "set_variable",
"value": 1215,
"variable": "baseKifayahAmount"
},
{
"id": "action-1-3",
"type": "set_variable",
"value": 780,
"variable": "spouseKifayahAmount"
}
],
"operator": "AND",
"conditions": [
{
"id": "condition-1-1",
"value": "berkahwin",
"operator": "eq",
"variable": "selectStatusperkahwinan"
},
{
"id": "condition-1-2",
"value": true,
"operator": "eq",
"variable": "hasDependents"
}
]
},
{
"id": "group-2",
"name": "Single with Dependents",
"actions": [
{
"id": "action-2-1",
"type": "set_variable",
"value": "single_with_dependents",
"variable": "householdType"
},
{
"id": "action-2-2",
"type": "set_variable",
"value": 1215,
"variable": "baseKifayahAmount"
},
{
"id": "action-2-3",
"type": "set_variable",
"value": 0,
"variable": "spouseKifayahAmount"
}
],
"operator": "AND",
"conditions": [
{
"id": "condition-2-1",
"value": "berkahwin",
"operator": "neq",
"variable": "selectStatusperkahwinan"
},
{
"id": "condition-2-2",
"value": true,
"operator": "eq",
"variable": "hasDependents"
}
]
},
{
"id": "group-3",
"name": "Calculate Dependent Allowance",
"actions": [
{
"id": "action-3-1",
"type": "set_variable",
"value": 408,
"variable": "dependentAllowance"
},
{
"id": "action-3-2",
"type": "set_variable",
"value": "school_age_7_17",
"variable": "dependentType"
}
],
"operator": "AND",
"conditions": [
{
"id": "condition-3-1",
"value": true,
"operator": "eq",
"variable": "hasDependents"
},
{
"id": "condition-3-2",
"value": "ya",
"operator": "eq",
"variable": "bersekolahTanggungan"
}
]
}
],
"description": "Calculate Had Kifayah based on household composition and income",
"errorVariable": "kifayahCalculationError",
"outputVariable": "kifayahCalculationResult"
},
"type": "business-rule",
"label": "Analisis Had Kifayah",
"position": { "x": 1485, "y": 45 }
},
{
"id": "notification-1751871950000",
"data": {
"label": "Hantar Keputusan Had Kifayah",
"message": "Assalamualaikum {applicantName},\n\nAnalisis Had Kifayah untuk permohonan anda dengan rujukan {applicationId} telah selesai.\n\n=== BUTIRAN ANALISIS HAD KIFAYAH ===\n\nJenis Isi Rumah: {householdType}\nJumlah Had Kifayah: RM {totalHadKifayah}\n\nPecahan:\n- Ketua Keluarga: RM {baseKifayahAmount}\n- Pasangan: RM {spouseKifayahAmount}\n- Tanggungan ({dependentCount} orang): RM {dependentAllowance}\n\nTarikh Analisis: {kifayahCalculationDate}\nStatus: {kifayahStatus}\n\nSila tunggu maklumat lanjut mengenai keputusan permohonan anda.\n\nTerima kasih.",
"subject": "Keputusan Analisis Had Kifayah - Permohonan {applicationId}",
"template": "kifayah-calculation-template",
"description": "Send Had Kifayah calculation results to applicant",
"errorVariable": "kifayahNotificationError",
"recipientType": "variable",
"recipientValue": "applicantEmail",
"notificationType": "email"
},
"type": "notification",
"label": "Hantar Keputusan Had Kifayah",
"position": { "x": 1890, "y": 30 }
},
{
"id": "notification-1751872000000",
"data": {
"label": "Terima Notifikasi",
"message": "Assalamualaikum {applicantName},\n\nPermohonan anda dengan rujukan {applicationId} tidak dapat diproses kerana dokumen yang dikemukakan tidak lengkap.\n\nSila lengkapkan dokumen yang diperlukan dan kemukakan semula permohonan anda.\n\nCatatan daripada pegawai pengesah:\n{verificationNotes}\n\nTerima kasih.",
"subject": "Dokumen Tidak Lengkap - Permohonan {applicationId}",
"template": "incomplete-documents-template",
"description": "Send notification for incomplete documents",
"errorVariable": "notificationError",
"recipientType": "variable",
"recipientValue": "applicantEmail",
"notificationType": "email"
},
"type": "notification",
"label": "Terima Notifikasi",
"position": { "x": 1485, "y": 360 }
},
{
"id": "end-1751872100000",
"data": {
"label": "End",
"description": "Process completion - documents incomplete"
},
"type": "end",
"label": "End",
"position": { "x": 1950, "y": 420 }
}
],
"viewport": {
"x": -117.3519061583577,
"y": 343.2355816226784,
"zoom": 0.7722385141739979
}
}

View File

@ -0,0 +1,707 @@
{
"text3": {
"name": "text3",
"type": "string",
"scope": "global",
"value": "Ahmad Bin Ali",
"description": "Applicant name from Section A"
},
"text14": {
"name": "text14",
"type": "string",
"scope": "global",
"value": "",
"description": "Other education specification from Section A"
},
"select1": {
"name": "select1",
"type": "string",
"scope": "global",
"value": "jeniskp_1",
"description": "ID type selection from Section A"
},
"apiError": {
"name": "apiError",
"type": "object",
"scope": "global",
"value": null,
"description": "API error from Submit Profile API"
},
"apiToken": {
"name": "apiToken",
"type": "string",
"scope": "global",
"value": "your-api-token-here",
"description": "API authentication token for external services"
},
"namaBank": {
"name": "namaBank",
"type": "string",
"scope": "global",
"value": "Maybank",
"description": "Bank name from Section B"
},
"radio9Copy": {
"name": "radio9Copy",
"type": "string",
"scope": "global",
"value": "tidak",
"description": "Currently studying status from Section A"
},
"sebabTunai": {
"name": "sebabTunai",
"type": "string",
"scope": "global",
"value": "",
"description": "Cash payment reason from Section B"
},
"verifiedBy": {
"name": "verifiedBy",
"type": "string",
"scope": "global",
"value": null,
"description": "User ID or name of person who verified documents"
},
"apiResponse": {
"name": "apiResponse",
"type": "object",
"scope": "global",
"value": {
"data": {
"id": "APP-2024-001234",
"score": 85,
"status": "pending_verification",
"profileId": "PROF-567890",
"riskLevel": "low",
"documentCount": 3,
"submissionDate": "2024-01-15T10:30:00Z"
},
"status": "success",
"message": "Profile submitted successfully"
},
"description": "API response from Submit Profile API"
},
"namaSekolah": {
"name": "namaSekolah",
"type": "string",
"scope": "global",
"value": "SMK Taman Desa",
"description": "Dependent school name from Section B"
},
"noAkaunBank": {
"name": "noAkaunBank",
"type": "string",
"scope": "global",
"value": "123456789012",
"description": "Bank account number from Section B"
},
"radioBangsa": {
"name": "radioBangsa",
"type": "string",
"scope": "global",
"value": "melayu",
"description": "Race from Section A"
},
"scriptError": {
"name": "scriptError",
"type": "object",
"scope": "global",
"value": null,
"description": "Error information from script execution"
},
"errorMessage": {
"name": "errorMessage",
"type": "string",
"scope": "global",
"value": null,
"description": "Error message from failed operations"
},
"formJeniskp1": {
"name": "formJeniskp1",
"type": "string",
"scope": "global",
"value": "123456789012",
"description": "MyKad/MyKid number from Section A"
},
"formJeniskp2": {
"name": "formJeniskp2",
"type": "string",
"scope": "global",
"value": "",
"description": "Passport/Police/Military ID number from Section A"
},
"formJeniskp3": {
"name": "formJeniskp3",
"type": "string",
"scope": "global",
"value": "",
"description": "Birth certificate number from Section A"
},
"okuAllowance": {
"name": "okuAllowance",
"type": "number",
"scope": "global",
"value": null,
"description": "OKU (disabled person) allowance (RM 247.00)"
},
"paymentReady": {
"name": "paymentReady",
"type": "boolean",
"scope": "global",
"value": true,
"description": "Whether payment processing is ready"
},
"profileScore": {
"name": "profileScore",
"type": "number",
"scope": "global",
"value": 85,
"description": "Profile score from initial API response"
},
"radioJantina": {
"name": "radioJantina",
"type": "string",
"scope": "global",
"value": "lelaki",
"description": "Gender from Section A"
},
"alamatSekolah": {
"name": "alamatSekolah",
"type": "string",
"scope": "global",
"value": "Jalan Desa Utama, Taman Desa, 58100 Kuala Lumpur",
"description": "Dependent school address from Section B"
},
"applicantName": {
"name": "applicantName",
"type": "string",
"scope": "global",
"value": "Ahmad Bin Ali",
"description": "Applicant name for verification form"
},
"applicationId": {
"name": "applicationId",
"type": "string",
"scope": "global",
"value": "APP-1751871528249",
"description": "Generated application ID from script processing"
},
"daerahSekolah": {
"name": "daerahSekolah",
"type": "string",
"scope": "global",
"value": "Kuala Lumpur",
"description": "Dependent school district from Section B"
},
"dependentName": {
"name": "dependentName",
"type": "string",
"scope": "global",
"value": "Siti Aminah Binti Ahmad",
"description": "Name of dependent"
},
"dependentType": {
"name": "dependentType",
"type": "string",
"scope": "global",
"value": null,
"description": "Type of dependent (school_age_7_17, below_6, etc.)"
},
"hasDependents": {
"name": "hasDependents",
"type": "boolean",
"scope": "global",
"value": true,
"description": "Whether applicant has dependents"
},
"householdType": {
"name": "householdType",
"type": "string",
"scope": "global",
"value": null,
"description": "Type of household (married_with_dependents, single_with_dependents, etc.)"
},
"kifayahStatus": {
"name": "kifayahStatus",
"type": "string",
"scope": "global",
"value": null,
"description": "Status of Had Kifayah calculation (calculated, pending, error)"
},
"negeriSekolah": {
"name": "negeriSekolah",
"type": "string",
"scope": "global",
"value": "Wilayah Persekutuan",
"description": "Dependent school state from Section B"
},
"nextStepReady": {
"name": "nextStepReady",
"type": "boolean",
"scope": "global",
"value": true,
"description": "Whether ready for next step in process"
},
"nyatakanLain2": {
"name": "nyatakanLain2",
"type": "string",
"scope": "global",
"value": "",
"description": "Other race specification from Section A"
},
"poskodSekolah": {
"name": "poskodSekolah",
"type": "string",
"scope": "global",
"value": "58100",
"description": "Dependent school postcode from Section B"
},
"applicantEmail": {
"name": "applicantEmail",
"type": "string",
"scope": "global",
"value": "ahmad.ali@example.com",
"description": "Applicant email address for notifications"
},
"caraPembayaran": {
"name": "caraPembayaran",
"type": "array",
"scope": "global",
"value": ["akaun"],
"description": "Payment method from Section B"
},
"dateMasukislam": {
"name": "dateMasukislam",
"type": "string",
"scope": "global",
"value": "2020-05-15",
"description": "Islam conversion date from Section A"
},
"dependentCount": {
"name": "dependentCount",
"type": "number",
"scope": "global",
"value": 1,
"description": "Number of dependents"
},
"hasBankingInfo": {
"name": "hasBankingInfo",
"type": "boolean",
"scope": "global",
"value": true,
"description": "Whether banking information is provided"
},
"namaTanggungan": {
"name": "namaTanggungan",
"type": "string",
"scope": "global",
"value": "Siti Aminah Binti Ahmad",
"description": "Dependent name from Section B"
},
"riskAssessment": {
"name": "riskAssessment",
"type": "string",
"scope": "global",
"value": null,
"description": "Risk assessment result from verification"
},
"radioPendidikan": {
"name": "radioPendidikan",
"type": "string",
"scope": "global",
"value": "ijazah",
"description": "Highest education level from Section A"
},
"rejectionReason": {
"name": "rejectionReason",
"type": "string",
"scope": "global",
"value": null,
"description": "Reason for rejection if documents incomplete"
},
"textWarganegara": {
"name": "textWarganegara",
"type": "string",
"scope": "global",
"value": "Malaysia",
"description": "Nationality from Section A"
},
"totalHadKifayah": {
"name": "totalHadKifayah",
"type": "number",
"scope": "global",
"value": null,
"description": "Total calculated Had Kifayah amount"
},
"bangsaTanggungan": {
"name": "bangsaTanggungan",
"type": "string",
"scope": "global",
"value": "melayu",
"description": "Dependent race from Section B"
},
"eligibilityScore": {
"name": "eligibilityScore",
"type": "number",
"scope": "global",
"value": null,
"description": "Eligibility score from verification API"
},
"hubunganKeluarga": {
"name": "hubunganKeluarga",
"type": "array",
"scope": "global",
"value": ["anak"],
"description": "Relationship with applicant from Section B"
},
"readyForDecision": {
"name": "readyForDecision",
"type": "boolean",
"scope": "global",
"value": null,
"description": "Whether ready for decision gateway"
},
"verificationDate": {
"name": "verificationDate",
"type": "string",
"scope": "global",
"value": null,
"description": "Date when verification was performed"
},
"baseKifayahAmount": {
"name": "baseKifayahAmount",
"type": "decimal",
"scope": "global",
"value": null,
"description": "Base Had Kifayah amount for head of household (RM 1,215.00)"
},
"documentsComplete": {
"name": "documentsComplete",
"type": "boolean",
"scope": "global",
"value": null,
"description": "Whether all documents are complete"
},
"documentsRequired": {
"name": "documentsRequired",
"type": "boolean",
"scope": "global",
"value": true,
"description": "Whether documents verification is required"
},
"jantinaTanggungan": {
"name": "jantinaTanggungan",
"type": "string",
"scope": "global",
"value": "perempuan",
"description": "Dependent gender from Section B"
},
"namaPemegangAkaun": {
"name": "namaPemegangAkaun",
"type": "string",
"scope": "global",
"value": "Ahmad Bin Ali",
"description": "Bank account holder name from Section B"
},
"notificationError": {
"name": "notificationError",
"type": "object",
"scope": "global",
"value": null,
"description": "Error from notification sending process"
},
"verificationError": {
"name": "verificationError",
"type": "string",
"scope": "global",
"value": null,
"description": "Error message from verification processing"
},
"verificationLevel": {
"name": "verificationLevel",
"type": "string",
"scope": "global",
"value": "enhanced",
"description": "Level of verification required (standard/enhanced)"
},
"verificationNotes": {
"name": "verificationNotes",
"type": "string",
"scope": "global",
"value": null,
"description": "Notes from document verification process"
},
"childcareAllowance": {
"name": "childcareAllowance",
"type": "number",
"scope": "global",
"value": null,
"description": "Childcare allowance for 12 years and below (RM 330.00)"
},
"dateMasukislamCopy": {
"name": "dateMasukislamCopy",
"type": "string",
"scope": "global",
"value": "2020-06-01",
"description": "KFAM start date from Section A"
},
"dependentAllowance": {
"name": "dependentAllowance",
"type": "decimal",
"scope": "global",
"value": null,
"description": "Allowance per dependent (RM 408.00 for school age 7-17)"
},
"jenisKadTanggungan": {
"name": "jenisKadTanggungan",
"type": "string",
"scope": "global",
"value": "mykad",
"description": "Dependent ID type from Section B"
},
"verificationStatus": {
"name": "verificationStatus",
"type": "string",
"scope": "global",
"value": null,
"description": "Status of document verification process"
},
"canProceedToKifayah": {
"name": "canProceedToKifayah",
"type": "boolean",
"scope": "global",
"value": null,
"description": "Whether process can proceed to kifayah analysis"
},
"noTelefonTanggungan": {
"name": "noTelefonTanggungan",
"type": "string",
"scope": "global",
"value": "03-12345678",
"description": "Dependent phone number from Section B"
},
"spouseKifayahAmount": {
"name": "spouseKifayahAmount",
"type": "decimal",
"scope": "global",
"value": null,
"description": "Had Kifayah amount for spouse (RM 780.00)"
},
"bangsaLainTanggungan": {
"name": "bangsaLainTanggungan",
"type": "string",
"scope": "global",
"value": "",
"description": "Dependent other race specification from Section B"
},
"bersekolahTanggungan": {
"name": "bersekolahTanggungan",
"type": "string",
"scope": "global",
"value": "ya",
"description": "Dependent currently studying from Section B"
},
"hubunganLainNyatakan": {
"name": "hubunganLainNyatakan",
"type": "string",
"scope": "global",
"value": "",
"description": "Other relationship specification from Section B"
},
"kifayahAnalysisError": {
"name": "kifayahAnalysisError",
"type": "object",
"scope": "global",
"value": null,
"description": "Error from kifayah analysis API call"
},
"verificationApiError": {
"name": "verificationApiError",
"type": "object",
"scope": "global",
"value": null,
"description": "Error from document verification API call"
},
"kifayahAnalysisResult": {
"name": "kifayahAnalysisResult",
"type": "object",
"scope": "global",
"value": null,
"description": "Result from kifayah eligibility analysis API"
},
"tarikhLahirTanggungan": {
"name": "tarikhLahirTanggungan",
"type": "string",
"scope": "global",
"value": "2010-03-15",
"description": "Dependent birth date from Section B"
},
"tempatLahirTanggungan": {
"name": "tempatLahirTanggungan",
"type": "string",
"scope": "global",
"value": "Hospital Kuala Lumpur",
"description": "Dependent birth place from Section B"
},
"verificationProcessed": {
"name": "verificationProcessed",
"type": "boolean",
"scope": "global",
"value": null,
"description": "Whether verification processing is complete"
},
"warganegaraTanggungan": {
"name": "warganegaraTanggungan",
"type": "string",
"scope": "global",
"value": "Malaysia",
"description": "Dependent nationality from Section B"
},
"kifayahCalculationDate": {
"name": "kifayahCalculationDate",
"type": "string",
"scope": "global",
"value": null,
"description": "Date and time when Had Kifayah was calculated"
},
"noPengenalanTanggungan": {
"name": "noPengenalanTanggungan",
"type": "string",
"scope": "global",
"value": "123456789013",
"description": "Dependent ID number from Section B"
},
"statusKahwinTanggungan": {
"name": "statusKahwinTanggungan",
"type": "string",
"scope": "global",
"value": "bujang",
"description": "Dependent marital status from Section B"
},
"tinggalBersamaKeluarga": {
"name": "tinggalBersamaKeluarga",
"type": "string",
"scope": "global",
"value": "ya",
"description": "Dependent lives with family from Section B"
},
"chronicIllnessAllowance": {
"name": "chronicIllnessAllowance",
"type": "number",
"scope": "global",
"value": null,
"description": "Chronic illness allowance (RM 243.00)"
},
"kifayahCalculationError": {
"name": "kifayahCalculationError",
"type": "object",
"scope": "global",
"value": null,
"description": "Error from Had Kifayah calculation"
},
"profileSubmissionStatus": {
"name": "profileSubmissionStatus",
"type": "string",
"scope": "global",
"value": "success",
"description": "Status of profile submission"
},
"selectStatusperkahwinan": {
"name": "selectStatusperkahwinan",
"type": "string",
"scope": "global",
"value": "berkahwin",
"description": "Marital status from Section A"
},
"tempatMenetapTanggungan": {
"name": "tempatMenetapTanggungan",
"type": "string",
"scope": "global",
"value": "13 Tahun",
"description": "Dependent residence duration in Selangor from Section B"
},
"verificationApiResponse": {
"name": "verificationApiResponse",
"type": "object",
"scope": "global",
"value": null,
"description": "Response from document verification API"
},
"verificationCompletedAt": {
"name": "verificationCompletedAt",
"type": "string",
"scope": "global",
"value": null,
"description": "Timestamp when verification was completed"
},
"verificationScriptError": {
"name": "verificationScriptError",
"type": "object",
"scope": "global",
"value": null,
"description": "Error from verification response processing script"
},
"kifayahCalculationResult": {
"name": "kifayahCalculationResult",
"type": "object",
"scope": "global",
"value": null,
"description": "Result from Had Kifayah business rule calculation"
},
"kifayahNotificationError": {
"name": "kifayahNotificationError",
"type": "object",
"scope": "global",
"value": null,
"description": "Error from sending Had Kifayah notification"
},
"pendidikanLainTanggungan": {
"name": "pendidikanLainTanggungan",
"type": "string",
"scope": "global",
"value": "",
"description": "Dependent other education specification from Section B"
},
"tarikhMulaKfamTanggungan": {
"name": "tarikhMulaKfamTanggungan",
"type": "string",
"scope": "global",
"value": "",
"description": "Dependent KFAM start date from Section B"
},
"dependentDocumentsComplete": {
"name": "dependentDocumentsComplete",
"type": "boolean",
"scope": "global",
"value": null,
"description": "Whether dependent documents are complete"
},
"documentVerificationResult": {
"name": "documentVerificationResult",
"type": "string",
"scope": "global",
"value": null,
"description": "Result from document verification form (lengkap/tidak_lengkap)"
},
"tarikhMasukIslamTanggungan": {
"name": "tarikhMasukIslamTanggungan",
"type": "string",
"scope": "global",
"value": "",
"description": "Dependent Islam conversion date from Section B"
},
"dependentVerificationStatus": {
"name": "dependentVerificationStatus",
"type": "string",
"scope": "global",
"value": null,
"description": "Dependent verification status"
},
"pendidikanTertinggiTanggungan": {
"name": "pendidikanTertinggiTanggungan",
"type": "array",
"scope": "global",
"value": ["smk"],
"description": "Dependent highest education from Section B"
}
}

View File

@ -0,0 +1,121 @@
# Node Color Customization
## Overview
The process builder now supports custom colors for nodes, allowing users to personalize the appearance of their process flows. Each node (except start and end nodes) can have customized background color, border color, and text color.
## Features
### Color Settings Panel
When a node is selected, the properties panel includes a "Color Settings" section with:
- **Background Color**: Color picker and text input for the node's background
- **Border Color**: Color picker and text input for the node's border
- **Text Color**: Color picker and text input for ALL text content in the node (title, descriptions, details, icons)
- **Reset Button**: Restores default colors with one click
### Supported Node Types
Color customization is available for:
- Form nodes
- API nodes
- Script nodes
- Business rule nodes
- Notification nodes
- Gateway/Decision nodes
### Shape Compatibility
Colors work with all supported node shapes:
- Rectangle
- Rounded Rectangle
- Circle
- Diamond
- Hexagon
- Parallelogram
- Trapezoid
## Usage
1. Select any node (except start/end nodes)
2. In the Properties panel, locate the "Color Settings" section
3. Use color pickers or enter hex values directly
4. Changes apply immediately to the canvas
5. Use "Reset to Default Colors" to restore original appearance
## Technical Implementation
### Color Storage
Colors are stored in the node's data object:
```javascript
{
backgroundColor: '#ffffff',
borderColor: '#ddd',
textColor: '#333333'
}
```
### CSS Variables
The implementation uses CSS custom properties for dynamic styling:
```css
--node-bg-color: backgroundColor
--node-border-color: borderColor
--node-text-color: textColor
```
### Backward Compatibility
Existing nodes without color properties automatically receive default values when selected or loaded.
## Default Colors
Each node type has its own distinctive color scheme:
### Form Nodes
- **Background**: `#faf5ff` (purple tint)
- **Border**: `#9333ea` (purple)
- **Text**: `#6b21a8` (dark purple)
### API Nodes
- **Background**: `#eff6ff` (blue tint)
- **Border**: `#3b82f6` (blue)
- **Text**: `#1e40af` (dark blue)
### Gateway/Decision Nodes
- **Background**: `#fff7ed` (orange tint)
- **Border**: `#f97316` (orange)
- **Text**: `#c2410c` (dark orange)
### Script Nodes
- **Background**: `#f9fafb` (gray tint)
- **Border**: `#6b7280` (gray)
- **Text**: `#374151` (dark gray)
### Business Rule Nodes
- **Background**: `#fdf4ff` (violet tint)
- **Border**: `#a855f7` (violet)
- **Text**: `#7c3aed` (dark violet)
### Notification Nodes
- **Background**: `#f0f9ff` (sky tint)
- **Border**: `#0ea5e9` (sky blue)
- **Text**: `#0284c7` (dark sky blue)
## Best Practices
### Accessibility
- Ensure sufficient contrast between text and background colors
- Test readability with different color combinations
- Consider colorblind users when choosing color schemes
- Text color affects ALL text elements in the node (titles, descriptions, details, and icons)
- Choose text colors that work well with your chosen background color
### Consistency
- Use consistent color schemes across related processes
- Consider using colors to indicate node types or priorities
- Document color meanings for team collaboration
### Performance
- Color changes are applied in real-time
- Colors persist when saving/loading processes
- No impact on process execution or functionality

File diff suppressed because it is too large Load Diff