<commit_before>var global = require('../../global');

module.exports = function (pox, offset) {

    var _items = pox.items.map(poItem => {
        // var productName = [poItem.product.name, po.refNo].filter(r => r && r.toString().trim() != '').join("\n");
        return {
            productName: poItem.product.name,
            productCode: poItem.product.code,
            productProperties: poItem.product.properties,
            productDesc: poItem.product.description,
            prNo: poItem.prNo,
            quantity: poItem.dealQuantity,
            uom: poItem.dealUom.unit,
            price: poItem.pricePerDealUnit,
            remark: poItem.remark
        };
    });

    _items = [].concat.apply([], _items);

    var items = [];
    var map = new Map();
    for (var _item of _items) {
        var key = _item.productName;
        if (!map.has(key))
            map.set(key, [])
        map.get(key).push(_item);
    }
    map.forEach((_items, productName) => {
        var poeItem = {};
        poeItem.productName = productName;
        poeItem.quantity = _items
            .map(_item => _item.quantity)
            .reduce((prev, curr, index) => {
                return prev + curr;
            }, 0);
        var prNos = [];
        _items
            .map(function (_item) {
                if (_item.prNo != "") {
                    prNos.push(_item.prNo);
                }
            })
        prNos = prNos.filter(function (elem, index, self) {
            return index == self.indexOf(elem);
        })
        poeItem.productCode = _items[0].productCode;
        poeItem.productProperties = _items[0].productProperties;
        poeItem.productDesc = _items[0].productDesc;
        poeItem.prNo = prNos.join("\n");
        poeItem.uom = _items[0].uom;
        poeItem.price = _items[0].price;

        var remaks = [];
        _items
            .map(function (_item) {
                if (_item.remark != "") {
                    remaks.push(_item.remark);
                }
            })
        poeItem.remark = remaks.join("\n");
        items.push(poeItem);
    });

    var iso = pox.category.code === "FAB" ? "FM-00-PJ-02-004" : "FM-PB-00-06-009/R1";
    var number = pox.no;
    var currency = pox.currency.code;
    var supplier = pox.supplier.name;
    var supplierAtt = pox.supplier.PIC;
    var supplierTel = pox.supplier.contact;

    var locale = global.config.locale;

    var moment = require('moment');
    moment.locale(locale.name);

    var header = [{
        text: 'PT. DAN LIRIS',
        style: 'bold'
    }, {
        columns: [{
            width: '50%',
            stack: [
                'Head Office   : ',
                'Kelurahan Banaran',
                'Kecamatan Grogol',
                'Sukoharjo 57193 - INDONESIA',
                'PO.BOX 166 Solo 57100',
                'Telp. (0271) 740888, 714400',
                'Fax. (0271) 735222, 740777'
            ],
            style: ['size07', 'bold']
        }, {
            stack: [{
                text: iso,
                alignment: "right",
                style: ['size08']
            }, {
                text: `Nomor PO : ${number}`,
                alignment: "right",
                style: ['size09', 'bold']
            }]

        }

        ]
    }, {
        alignment: "center",
        text: 'ORDER PEMBELIAN',
        style: ['size09', 'bold']
    },
        '\n'
    ];

    var attention = [{
        columns: [{
            width: '15%',
            text: 'Kepada Yth:',
            style: ['size08']
        }, {
            width: '*',
            text: `${supplier}\n Attn. ${supplierAtt}\n Telp. ${supplierTel}`,
            style: ['size08']
        }, {
            width: '35%',
            stack: [
                `Sukoharjo, ${moment(pox.date).add(offset, 'h').add(offset, 'h').format(locale.date.format)} `, {
                    text: [
                        'Mohon', {
                            text: ' di-fax kembali',
                            style: 'bold'
                        }, ' setelah\n', {
                            text: 'ditandatangani',
                            style: ['bold'],
                            decoration: 'underline'
                        }, ' dan ', {
                            text: 'distempel ',
                            style: ['bold'],
                            decoration: 'underline'
                        }, 'perusahaan.Terima Kasih.'
                    ],
                    style: ['size07']
                }
            ],
            style: ['size08']
        }]
    }];

    var opening = {
        text: [
            '\n', {
                text: 'Dengan hormat,\n'
            }, {
                text: 'Yang bertanda tangan di bawah ini, '
            }, {
                text: 'PT. DAN LIRIS, SOLO',
                style: ['bold']
            }, {
                text: ' (selanjutnya disebut sebagai pihak Pembeli) dan '
            }, {
                text: supplier,
                style: ['bold']
            }, {
                text: ' (selanjutnya disebut sebagai pihak Penjual) saling menyetujui untuk mengadakan kontrak jual beli dengan ketentuan sebagai berikut: '
            },
            '\n\n'
        ],
        style: ['size09', 'justify']
    };

    var thead = [{
        text: 'NAMA DAN JENIS BARANG',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'JUMLAH',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'HARGA SATUAN',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'SUB TOTAL',
        style: ['size08', 'bold', 'center']
    }];

    var tbody = []
    if (pox.category.code === "FAB") {
        tbody = items.map(function (item) {
            return [{
                stack: [item.productCode, item.productName, `COMPOSITON: ${item.productProperties[0]}`, `KONSTRUKSI: ${item.productProperties[1]}`, `YARN: ${item.productProperties[2]}`, item.productDesc, `Keterangan : ${item.remark}`, {
                    text: item.prNo,
                    style: 'bold'
                }],
                style: ['size08']
            }, {
                text: parseFloat(item.quantity).toLocaleString(locale, locale.decimal) + ' ' + item.uom,
                style: ['size08', 'center']
            }, {
                columns: [{
                    width: '20%',
                    text: `${currency}`
                }, {
                    width: '*',
                    text: `${parseFloat(item.price).toLocaleString(locale, locale.currency)}`,
                    style: ['right']
                }],
                style: ['size08']
            }, {
                columns: [{
                    width: '20%',
                    text: `${currency}`
                }, {
                    width: '*',
                    text: `${parseFloat(item.quantity * item.price).toLocaleString(locale, locale.currency)}`,
                    style: ['right']
                }],
                style: ['size08']
            }];
        });
    } else {
        tbody = items.map(function (item) {
            return [{
                stack: [`${item.productCode} - ${item.productName}`, item.productDesc, item.remark, {
                    text: item.prNo,
                    style: 'bold'
                }],
                style: ['size08']
            }, {
                text: parseFloat(item.quantity).toLocaleString(locale, locale.decimal) + ' ' + item.uom,
                style: ['size08', 'center']
            }, {
                columns: [{
                    width: '20%',
                    text: `${currency}`
                }, {
                    width: '*',
                    text: `${parseFloat(item.price).toLocaleString(locale, locale.currency)}`,
                    style: ['right']
                }],
                style: ['size08']
            }, {
                columns: [{
                    width: '20%',
                    text: `${currency}`
                }, {
                    width: '*',
                    text: `${parseFloat(item.quantity * item.price).toLocaleString(locale, locale.currency)}`,
                    style: ['right']
                }],
                style: ['size08']
            }];
        });
    }
    tbody = tbody.length > 0 ? tbody : [
        [{
            text: "tidak ada barang",
            style: ['size08', 'center'],
            colSpan: 4
        }, "", "", ""]
    ];
    var initialValue = {
        price: 0,
        quntity: 0
    };

    var sum = (items.length > 0 ? items : [initialValue])
        .map(item => item.price * item.quantity)
        .reduce(function (prev, curr, index, arr) {
            return prev + curr;
        }, 0);

    var vat = pox.useIncomeTax ? sum * 0.1 : 0;

    var tfoot = [
        [{
            text: 'Jumlah',
            style: ['size08', 'bold', 'right'],
            colSpan: 3
        }, "", "", {
            columns: [{
                width: '20%',
                text: currency
            }, {
                width: '*',
                text: parseFloat(sum).toLocaleString(locale, locale.currency),
                style: ['right']
            }],
            style: ['size08']
        }],
        [{
            text: 'PPN 10%',
            style: ['size08', 'bold', 'right'],
            colSpan: 3
        }, null, null, {
            columns: [{
                width: '20%',
                text: currency
            }, {
                width: '*',
                text: parseFloat(vat).toLocaleString(locale, locale.currency),
                style: ['right']
            }],
            style: ['size08']
        }],
        [{
            text: 'Grand Total',
            style: ['size08', 'bold', 'right'],
            colSpan: 3
        }, null, null, {
            columns: [{
                width: '20%',
                text: currency
            }, {
                width: '*',
                text: parseFloat(sum + vat).toLocaleString(locale, locale.currency),
                style: ['bold', 'right']
            }],
            style: ['size09']
        }]
    ];

    var table = [{
        table: {
            widths: ['*', '15%', '20%', '25%'],
            headerRows: 1,
            body: [].concat([thead], tbody, tfoot)
        }
    }];
    var footer = [
        '\n', {
            stack: [{
                columns: [{
                    width: '40%',
                    columns: [{
                        width: '40%',
                        stack: ['Ongkos Kirim', 'Pembayaran']
                    }, {
                        width: '3%',
                        stack: [':', ':']
                    }, {
                        width: '*',
                        stack: [`Ditanggung ${pox.freightCostBy}`, `${pox.paymentMethod}, ${pox.paymentDueDays} hari setelah terima barang`]
                    }]
                }, {
                    width: '20%',
                    text: ''
                }, {
                    width: '40%',
                    columns: [{
                        width: '45%',
                        stack: ['Delivery', 'Lain-lain']
                    }, {
                        width: '3%',
                        stack: [':', ':']
                    }, {
                        width: '*',
                        stack: [{
                            text: `${moment(pox.expectedDeliveryDate).add(offset, 'h').format(locale.date.format)}`,
                            style: ['bold']
                        }, `${pox.remark}`]
                    }]
                }]
            }],
            style: ['size08']
        }
    ];

    var stdQ = [
        '\n',
        {
            stack: [
                {
                    columns: [
                        {
                            width: '18%',
                            text: 'Standar Kualitas'
                        },
                        {
                            width: '2%',
                            text: ':'
                        },
                        {
                            width: '80%',
                            text: 'Jls; AATC; ISO'
                        }
                    ]
                },
                {
                    columns: [
                        {
                            width: '18%',
                            text: ' '
                        },
                        {
                            width: '2%',
                            text: ' '
                        },
                        {
                            width: '80%',
                            stack: [
                                {
                                    columns: [
                                        {
                                            width: '30%',
                                            text: 'Shringkage test untuk'
                                        }, {
                                            width: '2%',
                                            text: ' '
                                        }, {
                                            width: '68%',
                                            text: '..................................................................................%'
                                        }
                                    ]
                                },
                                {
                                    columns: [
                                        {
                                            width: '30%',
                                            text: 'Rubbing test'
                                        }, {
                                            width: '2%',
                                            text: ':'
                                        }, {
                                            width: '68%',
                                            text: 'WET Rubbing ...........................................................%'
                                        }
                                    ]
                                },
                                {
                                    columns: [
                                        {
                                            width: '30%',
                                            text: ' '
                                        }, {
                                            width: '2%',
                                            text: ' '
                                        }, {
                                            width: '68%',
                                            text: 'DRY Rubbing ...........................................................%'
                                        }
                                    ]
                                },
                                {
                                    columns: [
                                        {
                                            width: '30%',
                                            text: 'Washing test'
                                        }, {
                                            width: '2%',
                                            text: ':'
                                        }, {
                                            width: '68%',
                                            text: '..................................................................................%'
                                        }
                                    ]
                                },
                                {
                                    columns: [
                                        {
                                            width: '30%',
                                            text: 'Prespiration test'
                                        }, {
                                            width: '2%',
                                            text: ':'
                                        }, {
                                            width: '68%',
                                            text: 'Dark .........................................................................%'
                                        }
                                    ]
                                },
                                {
                                    columns: [
                                        {
                                            width: '30%',
                                            text: ' '
                                        }, {
                                            width: '2%',
                                            text: ' '
                                        }, {
                                            width: '68%',
                                            text: 'Light/Med ................................................................%'
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                },
                {
                    columns: [
                        {
                            width: '18%',
                            text: 'Piece Length'
                        },
                        {
                            width: '2%',
                            text: ':'
                        },
                        {
                            width: '80%',
                            stack: ['60 yards up 20%', '120 yards up to 80%']
                        }
                    ]
                }
            ], style: ['size08']
        }
    ];

    if (pox.category.code === "FAB") {
        footer.push(stdQ)
    }

    var signature = [
        '\n\n\n',
        {
            stack: [
                {
                    columns: [
                        {
                            width: '35%',
                            stack: ['Pembeli\n\n\n\n\n', {
                                text: pox._createdBy,
                                style: ['bold']
                            }],
                            style: 'center'
                        }, {
                            width: '30%',
                            text: ''
                        }, {
                            width: '35%',
                            stack: ['Penjual\n\n\n\n\n', {
                                text: supplier,
                                style: ['bold']
                            }],
                            style: 'center'
                        }]
                }
            ],
            style: ['size08']
        }
    ];

    var dd = {
        pageSize: 'A5',
        pageOrientation: 'portrait',
        pageMargins: 20,
        content: [].concat(header, attention, opening, table, footer, signature),
        styles: {
            size06: {
                fontSize: 6
            },
            size07: {
                fontSize: 7
            },
            size08: {
                fontSize: 8
            },
            size09: {
                fontSize: 9
            },
            size10: {
                fontSize: 10
            },
            bold: {
                bold: true
            },
            center: {
                alignment: 'center'
            },
            left: {
                alignment: 'left'
            },
            right: {
                alignment: 'right'
            },
            justify: {
                alignment: 'justify'
            }
        }
    };

    return dd;
};<commit_msg>bug fix : item barang dgn kode barang yg sama tidak perlu digabung<commit_after>var global = require('../../global');

module.exports = function (pox, offset) {

    var items = pox.items.map(poItem => {
         return {
            productName: poItem.product.name,
            productCode: poItem.product.code,
            productProperties: poItem.product.properties,
            productDesc: poItem.product.description,
            prNo: poItem.prNo,
            quantity: poItem.dealQuantity,
            uom: poItem.dealUom.unit,
            price: poItem.pricePerDealUnit,
            remark: poItem.remark
        };
    });

    items = [].concat.apply([], items);

    var iso = pox.category.code === "FAB" ? "FM-00-PJ-02-004" : "FM-PB-00-06-009/R1";
    var number = pox.no;
    var currency = pox.currency.code;
    var supplier = pox.supplier.name;
    var supplierAtt = pox.supplier.PIC;
    var supplierTel = pox.supplier.contact;

    var locale = global.config.locale;

    var moment = require('moment');
    moment.locale(locale.name);

    var header = [{
        text: 'PT. DAN LIRIS',
        style: 'bold'
    }, {
        columns: [{
            width: '50%',
            stack: [
                'Head Office   : ',
                'Kelurahan Banaran',
                'Kecamatan Grogol',
                'Sukoharjo 57193 - INDONESIA',
                'PO.BOX 166 Solo 57100',
                'Telp. (0271) 740888, 714400',
                'Fax. (0271) 735222, 740777'
            ],
            style: ['size07', 'bold']
        }, {
            stack: [{
                text: iso,
                alignment: "right",
                style: ['size08']
            }, {
                text: `Nomor PO : ${number}`,
                alignment: "right",
                style: ['size09', 'bold']
            }]

        }

        ]
    }, {
        alignment: "center",
        text: 'ORDER PEMBELIAN',
        style: ['size09', 'bold']
    },
        '\n'
    ];

    var attention = [{
        columns: [{
            width: '15%',
            text: 'Kepada Yth:',
            style: ['size08']
        }, {
            width: '*',
            text: `${supplier}\n Attn. ${supplierAtt}\n Telp. ${supplierTel}`,
            style: ['size08']
        }, {
            width: '35%',
            stack: [
                `Sukoharjo, ${moment(pox.date).add(offset, 'h').add(offset, 'h').format(locale.date.format)} `, {
                    text: [
                        'Mohon', {
                            text: ' di-fax kembali',
                            style: 'bold'
                        }, ' setelah\n', {
                            text: 'ditandatangani',
                            style: ['bold'],
                            decoration: 'underline'
                        }, ' dan ', {
                            text: 'distempel ',
                            style: ['bold'],
                            decoration: 'underline'
                        }, 'perusahaan.Terima Kasih.'
                    ],
                    style: ['size07']
                }
            ],
            style: ['size08']
        }]
    }];

    var opening = {
        text: [
            '\n', {
                text: 'Dengan hormat,\n'
            }, {
                text: 'Yang bertanda tangan di bawah ini, '
            }, {
                text: 'PT. DAN LIRIS, SOLO',
                style: ['bold']
            }, {
                text: ' (selanjutnya disebut sebagai pihak Pembeli) dan '
            }, {
                text: supplier,
                style: ['bold']
            }, {
                text: ' (selanjutnya disebut sebagai pihak Penjual) saling menyetujui untuk mengadakan kontrak jual beli dengan ketentuan sebagai berikut: '
            },
            '\n\n'
        ],
        style: ['size09', 'justify']
    };

    var thead = [{
        text: 'NAMA DAN JENIS BARANG',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'JUMLAH',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'HARGA SATUAN',
        style: ['size08', 'bold', 'center']
    }, {
        text: 'SUB TOTAL',
        style: ['size08', 'bold', 'center']
    }];

    var tbody = []
    if (pox.category.code === "FAB") {
        tbody = items.map(function (item) {
            return [{
                stack: [item.productCode, item.productName, `COMPOSITON: ${item.productProperties[0]}`, `KONSTRUKSI: ${item.productProperties[1]}`, `YARN: ${item.productProperties[2]}`, item.productDesc, `Keterangan : ${item.remark}`, {
                    text: item.prNo,
                    style: 'bold'
                }],
                style: ['size08']
            }, {
                text: parseFloat(item.quantity).toLocaleString(locale, locale.decimal) + ' ' + item.uom,
                style: ['size08', 'center']
            }, {
                columns: [{
                    width: '20%',
                    text: `${currency}`
                }, {
                    width: '*',
                    text: `${parseFloat(item.price).toLocaleString(locale, locale.currency)}`,
                    style: ['right']
                }],
                style: ['size08']
            }, {
                columns: [{
                    width: '20%',
                    text: `${currency}`
                }, {
                    width: '*',
                    text: `${parseFloat(item.quantity * item.price).toLocaleString(locale, locale.currency)}`,
                    style: ['right']
                }],
                style: ['size08']
            }];
        });
    } else {
        tbody = items.map(function (item) {
            return [{
                stack: [`${item.productCode} - ${item.productName}`, item.productDesc, item.remark, {
                    text: item.prNo,
                    style: 'bold'
                }],
                style: ['size08']
            }, {
                text: parseFloat(item.quantity).toLocaleString(locale, locale.decimal) + ' ' + item.uom,
                style: ['size08', 'center']
            }, {
                columns: [{
                    width: '20%',
                    text: `${currency}`
                }, {
                    width: '*',
                    text: `${parseFloat(item.price).toLocaleString(locale, locale.currency)}`,
                    style: ['right']
                }],
                style: ['size08']
            }, {
                columns: [{
                    width: '20%',
                    text: `${currency}`
                }, {
                    width: '*',
                    text: `${parseFloat(item.quantity * item.price).toLocaleString(locale, locale.currency)}`,
                    style: ['right']
                }],
                style: ['size08']
            }];
        });
    }
    tbody = tbody.length > 0 ? tbody : [
        [{
            text: "tidak ada barang",
            style: ['size08', 'center'],
            colSpan: 4
        }, "", "", ""]
    ];
    var initialValue = {
        price: 0,
        quntity: 0
    };

    var sum = (items.length > 0 ? items : [initialValue])
        .map(item => item.price * item.quantity)
        .reduce(function (prev, curr, index, arr) {
            return prev + curr;
        }, 0);

    var vat = pox.useIncomeTax ? sum * 0.1 : 0;

    var tfoot = [
        [{
            text: 'Jumlah',
            style: ['size08', 'bold', 'right'],
            colSpan: 3
        }, "", "", {
            columns: [{
                width: '20%',
                text: currency
            }, {
                width: '*',
                text: parseFloat(sum).toLocaleString(locale, locale.currency),
                style: ['right']
            }],
            style: ['size08']
        }],
        [{
            text: 'PPN 10%',
            style: ['size08', 'bold', 'right'],
            colSpan: 3
        }, null, null, {
            columns: [{
                width: '20%',
                text: currency
            }, {
                width: '*',
                text: parseFloat(vat).toLocaleString(locale, locale.currency),
                style: ['right']
            }],
            style: ['size08']
        }],
        [{
            text: 'Grand Total',
            style: ['size08', 'bold', 'right'],
            colSpan: 3
        }, null, null, {
            columns: [{
                width: '20%',
                text: currency
            }, {
                width: '*',
                text: parseFloat(sum + vat).toLocaleString(locale, locale.currency),
                style: ['bold', 'right']
            }],
            style: ['size09']
        }]
    ];

    var table = [{
        table: {
            widths: ['*', '15%', '20%', '25%'],
            headerRows: 1,
            body: [].concat([thead], tbody, tfoot)
        }
    }];
    var footer = [
        '\n', {
            stack: [{
                columns: [{
                    width: '40%',
                    columns: [{
                        width: '40%',
                        stack: ['Ongkos Kirim', 'Pembayaran']
                    }, {
                        width: '3%',
                        stack: [':', ':']
                    }, {
                        width: '*',
                        stack: [`Ditanggung ${pox.freightCostBy}`, `${pox.paymentMethod}, ${pox.paymentDueDays} hari setelah terima barang`]
                    }]
                }, {
                    width: '20%',
                    text: ''
                }, {
                    width: '40%',
                    columns: [{
                        width: '45%',
                        stack: ['Delivery', 'Lain-lain']
                    }, {
                        width: '3%',
                        stack: [':', ':']
                    }, {
                        width: '*',
                        stack: [{
                            text: `${moment(pox.expectedDeliveryDate).add(offset, 'h').format(locale.date.format)}`,
                            style: ['bold']
                        }, `${pox.remark}`]
                    }]
                }]
            }],
            style: ['size08']
        }
    ];

    var stdQ = [
        '\n',
        {
            stack: [
                {
                    columns: [
                        {
                            width: '18%',
                            text: 'Standar Kualitas'
                        },
                        {
                            width: '2%',
                            text: ':'
                        },
                        {
                            width: '80%',
                            text: 'Jls; AATC; ISO'
                        }
                    ]
                },
                {
                    columns: [
                        {
                            width: '18%',
                            text: ' '
                        },
                        {
                            width: '2%',
                            text: ' '
                        },
                        {
                            width: '80%',
                            stack: [
                                {
                                    columns: [
                                        {
                                            width: '30%',
                                            text: 'Shringkage test untuk'
                                        }, {
                                            width: '2%',
                                            text: ' '
                                        }, {
                                            width: '68%',
                                            text: '..................................................................................%'
                                        }
                                    ]
                                },
                                {
                                    columns: [
                                        {
                                            width: '30%',
                                            text: 'Rubbing test'
                                        }, {
                                            width: '2%',
                                            text: ':'
                                        }, {
                                            width: '68%',
                                            text: 'WET Rubbing ...........................................................%'
                                        }
                                    ]
                                },
                                {
                                    columns: [
                                        {
                                            width: '30%',
                                            text: ' '
                                        }, {
                                            width: '2%',
                                            text: ' '
                                        }, {
                                            width: '68%',
                                            text: 'DRY Rubbing ...........................................................%'
                                        }
                                    ]
                                },
                                {
                                    columns: [
                                        {
                                            width: '30%',
                                            text: 'Washing test'
                                        }, {
                                            width: '2%',
                                            text: ':'
                                        }, {
                                            width: '68%',
                                            text: '..................................................................................%'
                                        }
                                    ]
                                },
                                {
                                    columns: [
                                        {
                                            width: '30%',
                                            text: 'Prespiration test'
                                        }, {
                                            width: '2%',
                                            text: ':'
                                        }, {
                                            width: '68%',
                                            text: 'Dark .........................................................................%'
                                        }
                                    ]
                                },
                                {
                                    columns: [
                                        {
                                            width: '30%',
                                            text: ' '
                                        }, {
                                            width: '2%',
                                            text: ' '
                                        }, {
                                            width: '68%',
                                            text: 'Light/Med ................................................................%'
                                        }
                                    ]
                                }
                            ]
                        }
                    ]
                },
                {
                    columns: [
                        {
                            width: '18%',
                            text: 'Piece Length'
                        },
                        {
                            width: '2%',
                            text: ':'
                        },
                        {
                            width: '80%',
                            stack: ['60 yards up 20%', '120 yards up to 80%']
                        }
                    ]
                }
            ], style: ['size08']
        }
    ];

    if (pox.category.code === "FAB") {
        footer.push(stdQ)
    }

    var signature = [
        '\n\n\n',
        {
            stack: [
                {
                    columns: [
                        {
                            width: '35%',
                            stack: ['Pembeli\n\n\n\n\n', {
                                text: pox._createdBy,
                                style: ['bold']
                            }],
                            style: 'center'
                        }, {
                            width: '30%',
                            text: ''
                        }, {
                            width: '35%',
                            stack: ['Penjual\n\n\n\n\n', {
                                text: supplier,
                                style: ['bold']
                            }],
                            style: 'center'
                        }]
                }
            ],
            style: ['size08']
        }
    ];

    var dd = {
        pageSize: 'A5',
        pageOrientation: 'portrait',
        pageMargins: 20,
        content: [].concat(header, attention, opening, table, footer, signature),
        styles: {
            size06: {
                fontSize: 6
            },
            size07: {
                fontSize: 7
            },
            size08: {
                fontSize: 8
            },
            size09: {
                fontSize: 9
            },
            size10: {
                fontSize: 10
            },
            bold: {
                bold: true
            },
            center: {
                alignment: 'center'
            },
            left: {
                alignment: 'left'
            },
            right: {
                alignment: 'right'
            },
            justify: {
                alignment: 'justify'
            }
        }
    };

    return dd;
};<|endoftext|>


<commit_before>// TODO: Add back this line when the website rewrite is done
// \n • Your name and a custom phrase on [RemindMeBot\'s website](http://remindmebot.xyz/) (At least $2.00)
async function donateCommand (Bot, msg) {
  Bot.sendMessage(msg.channel.id, { embed: {
    description: 'RemindMeBot will always remain a free service. However, if you would like to donate, you can do so [here](https://paypal.me/Aether2017) (PayPal) or to `18UNsWHGvskZSxKc6LvyaqwKk5FUf2af4D` (BTC).\n\nAs a donator, you will receive:\n • A `Donator` role on [RemindMeBot Support](https://discord.gg/Yphr6WG) (Any amount)\n • Your name and a custom phrase on this command (At least $1.00)\n • Lots of hugs & kisses from Aetheryx (Any amount :kissing_heart:)\n\u200b',
    fields: [
      { name: 'Donators so far', value: 'None! You should totally be the first.' }
    ],
    footer: { text: 'If you do decide to donate, please DM Aetheryx#2222 with proof.' }
  }});
}

module.exports = {
  call: donateCommand,
  name: 'donate',
  description: 'Returns information regarding donations.'
}<commit_msg>Break up string<commit_after>// TODO: Add back this line when the website rewrite is done
// \n • Your name and a custom phrase on [RemindMeBot\'s website](http://remindmebot.xyz/) (At least $2.00)
async function donateCommand (Bot, msg) {
  Bot.sendMessage(msg.channel.id, { embed: {
    description: 'RemindMeBot will always remain a free service. However, if you would like to donate, you can do so [here](https://paypal.me/Aether2017) (PayPal) or to `18UNsWHGvskZSxKc6LvyaqwKk5FUf2af4D` (BTC).' +
    '\n\nAs a donator, you will receive:\n' +
    ' • A `Donator` role on [RemindMeBot Support](https://discord.gg/Yphr6WG) (Any amount)\n' +
    ' • Your name and a custom phrase on this command (At least $1.00)\n' +
    ' • Lots of hugs & kisses from Aetheryx (Any amount :kissing_heart:)\n\u200b',
    fields: [
      { name: 'Donators so far', value: 'None! You should totally be the first.' }
    ],
    footer: { text: 'If you do decide to donate, please DM Aetheryx#2222 with proof.' }
  }});
}

module.exports = {
  call: donateCommand,
  name: 'donate',
  description: 'Returns information regarding donations.'
}<|endoftext|>


<commit_before>import { EXTERNAL_APPS, EXTERNAL_REDIRECTS } from '../constants';
import {
  defaultSignUpProviders,
  defaultSignInProviders,
  defaultMobileQueryParams,
} from './constants';

export default {
  default: {
    allowedSignInProviders: { ...defaultSignInProviders },
    allowedSignUpProviders: { ...defaultSignUpProviders },
    isMobile: false,
    queryParams: {
      allowOAuth: true,
      allowPostLogin: true,
      allowRedirect: false,
    },
    OAuthEnabled: false,
    requiresVerification: false,
  },
  [EXTERNAL_APPS.MHV]: {
    allowedSignInProviders: { ...defaultSignInProviders },
    allowedSignUpProviders: { ...defaultSignUpProviders },
    isMobile: false,
    queryParams: {
      allowOAuth: false,
      allowPostLogin: true,
      allowRedirect: true,
    },
    OAuthEnabled: false,
    requiresVerification: false,
    externalRedirectUrl: EXTERNAL_REDIRECTS[EXTERNAL_APPS.MHV],
  },
  [EXTERNAL_APPS.MY_VA_HEALTH]: {
    allowedSignInProviders: { ...defaultSignInProviders },
    allowedSignUpProviders: { ...defaultSignUpProviders },
    isMobile: false,
    queryParams: {
      allowOAuth: false,
      allowPostLogin: false,
      allowRedirect: false,
    },
    OAuthEnabled: false,
    requiresVerification: false,
    externalRedirectUrl: EXTERNAL_REDIRECTS[EXTERNAL_APPS.MY_VA_HEALTH],
  },
  [EXTERNAL_APPS.EBENEFITS]: {
    allowedSignInProviders: { ...defaultSignInProviders },
    allowedSignUpProviders: { ...defaultSignUpProviders },
    isMobile: false,
    queryParams: {
      allowOAuth: false,
      allowPostLogin: false,
      allowRedirect: false,
    },
    OAuthEnabled: false,
    requiresVerification: false,
    externalRedirectUrl: EXTERNAL_REDIRECTS[EXTERNAL_APPS.EBENEFITS],
  },
  [EXTERNAL_APPS.VA_FLAGSHIP_MOBILE]: {
    allowedSignInProviders: { ...defaultSignInProviders },
    allowedSignUpProviders: { ...defaultSignUpProviders },
    isMobile: true,
    queryParams: { ...defaultMobileQueryParams },
    OAuthEnabled: true,
    requiresVerification: true,
    externalRedirectUrl: EXTERNAL_REDIRECTS[EXTERNAL_APPS.VA_FLAGSHIP_MOBILE],
  },
  [EXTERNAL_APPS.VA_OCC_MOBILE]: {
    allowedSignInProviders: { ...defaultSignInProviders },
    allowedSignUpProviders: { ...defaultSignUpProviders },
    isMobile: true,
    queryParams: { ...defaultMobileQueryParams },
    OAuthEnabled: true,
    requiresVerification: true,
    externalRedirectUrl: EXTERNAL_REDIRECTS[EXTERNAL_APPS.VA_OCC_MOBILE],
  },
};
<commit_msg>updates correct config (#21776)<commit_after>import { EXTERNAL_APPS, EXTERNAL_REDIRECTS } from '../constants';
import {
  defaultSignUpProviders,
  defaultSignInProviders,
  defaultMobileQueryParams,
} from './constants';

export default {
  default: {
    allowedSignInProviders: { ...defaultSignInProviders },
    allowedSignUpProviders: { ...defaultSignUpProviders },
    isMobile: false,
    queryParams: {
      allowOAuth: true,
      allowPostLogin: true,
      allowRedirect: false,
    },
    OAuthEnabled: true,
    requiresVerification: false,
  },
  [EXTERNAL_APPS.MHV]: {
    allowedSignInProviders: { ...defaultSignInProviders },
    allowedSignUpProviders: { ...defaultSignUpProviders },
    isMobile: false,
    queryParams: {
      allowOAuth: false,
      allowPostLogin: true,
      allowRedirect: true,
    },
    OAuthEnabled: false,
    requiresVerification: false,
    externalRedirectUrl: EXTERNAL_REDIRECTS[EXTERNAL_APPS.MHV],
  },
  [EXTERNAL_APPS.MY_VA_HEALTH]: {
    allowedSignInProviders: { ...defaultSignInProviders },
    allowedSignUpProviders: { ...defaultSignUpProviders },
    isMobile: false,
    queryParams: {
      allowOAuth: false,
      allowPostLogin: false,
      allowRedirect: false,
    },
    OAuthEnabled: false,
    requiresVerification: false,
    externalRedirectUrl: EXTERNAL_REDIRECTS[EXTERNAL_APPS.MY_VA_HEALTH],
  },
  [EXTERNAL_APPS.EBENEFITS]: {
    allowedSignInProviders: { ...defaultSignInProviders },
    allowedSignUpProviders: { ...defaultSignUpProviders },
    isMobile: false,
    queryParams: {
      allowOAuth: false,
      allowPostLogin: false,
      allowRedirect: false,
    },
    OAuthEnabled: false,
    requiresVerification: false,
    externalRedirectUrl: EXTERNAL_REDIRECTS[EXTERNAL_APPS.EBENEFITS],
  },
  [EXTERNAL_APPS.VA_FLAGSHIP_MOBILE]: {
    allowedSignInProviders: { ...defaultSignInProviders },
    allowedSignUpProviders: { ...defaultSignUpProviders },
    isMobile: true,
    queryParams: { ...defaultMobileQueryParams },
    OAuthEnabled: true,
    requiresVerification: true,
    externalRedirectUrl: EXTERNAL_REDIRECTS[EXTERNAL_APPS.VA_FLAGSHIP_MOBILE],
  },
  [EXTERNAL_APPS.VA_OCC_MOBILE]: {
    allowedSignInProviders: { ...defaultSignInProviders },
    allowedSignUpProviders: { ...defaultSignUpProviders },
    isMobile: true,
    queryParams: { ...defaultMobileQueryParams },
    OAuthEnabled: true,
    requiresVerification: true,
    externalRedirectUrl: EXTERNAL_REDIRECTS[EXTERNAL_APPS.VA_OCC_MOBILE],
  },
};
<|endoftext|>


<commit_before>const SelectMatcher    = require('@binary-com/binary-style').select2Matcher;
const moment           = require('moment');
const BinaryPjax       = require('../../../../base/binary_pjax');
const Client           = require('../../../../base/client');
const Header           = require('../../../../base/header');
const BinarySocket     = require('../../../../base/socket');
const formatMoney      = require('../../../../common/currency').formatMoney;
const FormManager      = require('../../../../common/form_manager');
const Geocoder         = require('../../../../../_common/geocoder');
const CommonFunctions  = require('../../../../../_common/common_functions');
const localize         = require('../../../../../_common/localize').localize;
const State            = require('../../../../../_common/storage').State;
const getPropertyValue = require('../../../../../_common/utility').getPropertyValue;

const PersonalDetails = (() => {
    const form_id           = '#frmPersonalDetails';
    const real_acc_elements = '.RealAcc';

    let is_for_new_account = false;

    let editable_fields,
        is_virtual,
        residence,
        get_settings_data,
        currency;

    const init = () => {
        editable_fields   = {};
        get_settings_data = {};
        is_virtual        = Client.get('is_virtual');
        residence         = Client.get('residence');
    };

    const showHideTaxMessage = () => {
        const $tax_info_declaration = $('#tax_information_declaration');
        const $tax_information_info = $('#tax_information_info');

        if (Client.shouldCompleteTax()) {
            $('#tax_information_note_toggle').off('click').on('click', (e) => {
                e.stopPropagation();
                $('#tax_information_note_toggle').toggleClass('open');
                $('#tax_information_note').slideToggle();
            });
        } else {
            $tax_information_info.setVisibility(0); // hide tax info
            $tax_info_declaration.setVisibility(0); // hide tax info declaration
        }
    };

    const showHideLabel = (get_settings) => {
        ['place_of_birth', 'account_opening_reason', 'citizen'].forEach((id) => {
            if (Object.prototype.hasOwnProperty.call(get_settings, id)) {
                if (get_settings[id]) {
                    // we have to show text here instead of relying on displayGetSettingsData()
                    // since it prioritizes showing data instead of label
                    const $label = $(`#lbl_${id}`);
                    $label.text(get_settings[id]);
                    $(`#row_${id}`).setVisibility(0);
                    $(`#row_lbl_${id}`).setVisibility(1);
                } else {
                    $(`#row_lbl_${id}`).setVisibility(0);
                    $(`#row_${id}`).setVisibility(1);
                }
            }
        });
    };

    const showHideMissingDetails = () => {
        const validations = getValidations();
        const has_missing_field = validations.find((validation) => /req/.test(validation.validations) && $(validation.selector).val() === '');
        $('#missing_details_notice').setVisibility(!!has_missing_field);
    };

    const getDetailsResponse = (data, residence_list = State.getResponse('residence_list')) => {
        const get_settings         = $.extend({}, data);
        get_settings.date_of_birth = 'date_of_birth' in get_settings ? moment.utc(new Date(get_settings.date_of_birth * 1000)).format('YYYY-MM-DD') : '';
        const accounts             = Client.getAllLoginids();
        // for subaccounts, back-end sends loginid of the master account as name
        const hide_name            = accounts.some(loginid => new RegExp(loginid, 'i').test(get_settings.first_name)) || is_virtual;
        if (!hide_name) {
            get_settings.name = `${(get_settings.salutation || '')} ${(get_settings.first_name || '')} ${(get_settings.last_name || '')}`;
        }

        if (get_settings.place_of_birth) {
            get_settings.place_of_birth =
                (residence_list.find(obj => obj.value === get_settings.place_of_birth) || {}).text ||
                get_settings.place_of_birth;
        }

        if (get_settings.citizen) {
            get_settings.citizen =
                (residence_list.find(obj => obj.value === get_settings.citizen) || {}).text ||
                get_settings.citizen;
        }

        showHideLabel(get_settings);

        displayGetSettingsData(get_settings);

        if (is_virtual) {
            $(real_acc_elements).remove();
        } else {
            $(real_acc_elements).setVisibility(1);
            showHideTaxMessage();
        }
        $(form_id).setVisibility(1);
        $('#loading').remove();
        FormManager.init(form_id, getValidations());
        FormManager.handleSubmit({
            form_selector       : form_id,
            obj_request         : { set_settings: 1 },
            fnc_response_handler: setDetailsResponse,
            fnc_additional_check: additionalCheck,
            enable_button       : true,
        });
        if (!is_virtual) {
            Geocoder.validate(form_id);
        }
        showHideMissingDetails();
    };

    const displayGetSettingsData = (data, populate = true) => {
        let el_key,
            data_key;
        Object.keys(data).forEach((key) => {
            el_key = document.getElementById(key) || document.getElementById(`lbl_${key}`);
            if (el_key) {
                data_key             = /format_money/.test(el_key.className) && data[key] !== null ? formatMoney(currency, data[key]) : (data[key] || '');
                editable_fields[key] = data_key;
                if (populate) {
                    if (el_key.type === 'checkbox') {
                        el_key.checked = !!data_key;
                    } else if (/select|text/i.test(el_key.type)) {
                        $(el_key)
                            .val(data_key.split(','))
                            .trigger('change');
                    } else if (key !== 'country') {
                        CommonFunctions.elementInnerHtml(el_key, data_key ? localize(data_key) : '-');
                    }
                }
            }
        });
        if (data.country) {
            $('#residence').replaceWith($('<label/>').append($('<strong/>', { id: 'lbl_country' })));
            $('#lbl_country').text(data.country);
        }
    };

    const additionalCheck = (data) => {
        if (!isChanged(data)) {
            showFormMessage('You did not change anything.', false);
            return false;
        }
        return true;
    };

    const isChanged = (data) => {
        const compare_data = $.extend({}, data);
        return Object.keys(compare_data).some(key => (
            key !== 'set_settings' && editable_fields[key] !== compare_data[key]
        ));
    };

    const getValidations = () => {
        let validations;
        if (is_virtual) {
            validations = [
                { selector: '#email_consent' },
                { selector: '#residence', validations: ['req'] },
            ];
        } else {
            const is_financial      = Client.isAccountOfType('financial');
            const is_gaming         = Client.isAccountOfType('gaming');
            const mt_acct_type      = localStorage.getItem('personal_details_redirect');
            const is_for_mt_citizen = !!mt_acct_type;                                                   // all mt account opening requires citizen
            const is_for_mt_tax     = /real/.test(mt_acct_type) && mt_acct_type.split('_').length > 2;  // demo and volatility mt accounts do not require tax info
            const is_tax_req        = is_financial || (is_for_mt_tax && +State.getResponse('landing_company.config.tax_details_required') === 1);

            validations = [
                { selector: '#address_line_1',         validations: ['req', 'address'] },
                { selector: '#address_line_2',         validations: ['address'] },
                { selector: '#address_city',           validations: ['req', 'letter_symbol'] },
                { selector: '#address_state',          validations: $('#address_state').prop('nodeName') === 'SELECT' ? '' : ['letter_symbol'] },
                { selector: '#address_postcode',       validations: [Client.get('residence') === 'gb' ? 'req' : '', 'postcode', ['length', { min: 0, max: 20 }]] },
                { selector: '#email_consent' },
                { selector: '#phone',                  validations: ['req', 'phone', ['length', { min: 6, max: 35, value: () => $('#phone').val().replace(/^\+/, '')  }]] },
                { selector: '#place_of_birth',         validations: ['req'] },
                { selector: '#account_opening_reason', validations: ['req'] },

                { selector: '#tax_residence',  validations: (is_tax_req) ? ['req'] : '' },
                { selector: '#citizen',        validations: (is_financial || is_gaming || is_for_mt_citizen) ? ['req'] : '' },
                { selector: '#chk_tax_id',     validations: is_financial ? [['req', { hide_asterisk: true, message: localize('Please confirm that all the information above is true and complete.') }]] : '', exclude_request: 1 },
            ];

            const tax_id_validation  = { selector: '#tax_identification_number', validations: ['tax_id', ['length', { min: 0, max: 20 }]] };
            if (is_tax_req) {
                tax_id_validation.validations[1][1].min = 1;
                tax_id_validation.validations.unshift('req');
            }
            validations.push(tax_id_validation);
        }
        return validations;
    };

    const setDetailsResponse = (response) => {
        // allow user to resubmit the form on error.
        const is_error = response.set_settings !== 1;
        if (!is_error) {
            const redirect_url = localStorage.getItem('personal_details_redirect');
            // to update tax information message for financial clients
            BinarySocket.send({ get_account_status: 1 }, { forced: true }).then((response_status) => {
                showHideTaxMessage();
                Header.displayAccountStatus();
                if (redirect_url && +response_status.get_account_status.prompt_client_to_authenticate && Client.isAccountOfType('financial')) {
                    $('#msg_authenticate').setVisibility(1);
                }
            });
            // to update the State with latest get_settings data
            BinarySocket.send({ get_settings: 1 }, { forced: true }).then((data) => {
                if (is_virtual && response.echo_req.residence) {
                    window.location.reload(); // reload page if we are setting residence
                    return;
                }
                // update notification shown for set residence etc
                Header.displayAccountStatus();
                if (is_for_new_account) {
                    is_for_new_account = false;
                    BinaryPjax.loadPreviousUrl();
                    return;
                }
                const get_settings    = data.get_settings;
                const has_required_mt = (State.getResponse('landing_company.config.tax_details_required') !== 1 ?
                    get_settings.citizen // only check Citizen if tax details are not required
                    :
                    (get_settings.tax_residence && get_settings.tax_identification_number && get_settings.citizen));
                if (redirect_url && has_required_mt) {
                    localStorage.removeItem('personal_details_redirect');
                    $.scrollTo($('h1#heading'), 500, { offset: -10 });
                    $(form_id).setVisibility(0);
                    $('#missing_details_notice').setVisibility(0);
                    $('.rowCustomerSupport').setVisibility(0);
                    $('#msg_main').setVisibility(1);
                    return;
                }
                getDetailsResponse(get_settings);
            });
        }
        showFormMessage(is_error ?
            (getPropertyValue(response, ['error', 'message']) || 'Sorry, an error occurred while processing your account.') :
            'Your settings have been updated successfully.', !is_error);
    };

    const showFormMessage = (msg, is_success) => {
        $('#formMessage')
            .attr('class', is_success ? 'success-msg' : 'errorfield')
            .html(is_success ? $('<ul/>', { class: 'checked' }).append($('<li/>', { text: localize(msg) })) : localize(msg))
            .css('display', 'block')
            .delay(5000)
            .fadeOut(1000);
    };

    const populateResidence = (response) => (
        new Promise((resolve) => {
            const residence_list = response.residence_list;
            if (residence_list.length > 0) {
                const $options               = $('<div/>');
                const $options_with_disabled = $('<div/>');
                residence_list.forEach((res) => {
                    $options.append(CommonFunctions.makeOption({ text: res.text, value: res.value }));
                    $options_with_disabled.append(CommonFunctions.makeOption({
                        text       : res.text,
                        value      : res.value,
                        is_disabled: res.disabled,
                    }));
                });

                if (residence) {
                    const $tax_residence = $('#tax_residence');
                    $tax_residence.html($options_with_disabled.html()).promise().done(() => {
                        setTimeout(() => {
                            $tax_residence.select2()
                                .val(get_settings_data.tax_residence ? get_settings_data.tax_residence.split(',') : '')
                                .trigger('change')
                                .setVisibility(1);
                        }, 500);
                    });

                    if (!get_settings_data.place_of_birth) {
                        $options.prepend($('<option/>', { value: '', text: localize('Please select') }));
                        $('#place_of_birth')
                            .html($options.html())
                            .val(residence);
                    }

                    if (!get_settings_data.citizen) {
                        $options.prepend($('<option/>', { value: '', text: localize('Please select') }));
                        $('#citizen')
                            .html($options.html())
                            .val(residence);
                    }
                } else {
                    $('#lbl_country').parent().replaceWith($('<select/>', { id: 'residence', single: 'single' }));
                    const $residence = $('#residence');
                    $options_with_disabled.prepend($('<option/>', { text: localize('Please select a country'), value: '' }));
                    $residence.html($options_with_disabled.html());
                    $residence.select2({
                        matcher(params, data) {
                            return SelectMatcher(params, data);
                        },
                    });
                }
            }
            resolve();
        })
    );

    const populateStates = (response) => (
        new Promise((resolve) => {
            const states = response.states_list;

            const address_state = '#address_state';
            let $field          = $(address_state);

            $field.empty();

            if (states && states.length > 0) {
                $field.append($('<option/>', { value: '', text: localize('Please select') }));
                states.forEach((state) => {
                    $field.append($('<option/>', { value: state.value, text: state.text }));
                });
            } else {
                $field.replaceWith($('<input/>', { id: address_state.replace('#', ''), name: 'address_state', type: 'text', maxlength: '35', 'data-lpignore': true }));
                $field = $(address_state);
            }
            $field.val(get_settings_data.address_state);

            if (states && states.length > 0) {
                $('#address_state').select2({
                    matcher(params, data) {
                        return SelectMatcher(params, data);
                    },
                });
            }
            $field.val(get_settings_data.address_state);

            resolve();
        })
    );

    const onLoad = () => {
        currency = Client.get('currency');
        BinarySocket.wait('get_account_status', 'get_settings', 'landing_company').then(() => {
            init();
            get_settings_data = State.getResponse('get_settings');

            if (is_virtual) {
                getDetailsResponse(get_settings_data);
            }

            if (!is_virtual || !residence) {
                BinarySocket.send({ residence_list: 1 }).then(response => {
                    populateResidence(response).then(() => {
                        if (residence) {
                            BinarySocket.send({ states_list: residence }).then(response_state => {
                                populateStates(response_state).then(() => {
                                    getDetailsResponse(get_settings_data, response.residence_list);
                                });
                            });
                        } else {
                            getDetailsResponse(get_settings_data, response.residence_list);
                        }
                        $('#place_of_birth, #citizen').select2({
                            matcher(params, data) {
                                return SelectMatcher(params, data);
                            },
                        });
                    });
                });
            }
        });
    };

    const onUnload = () => {
        is_for_new_account = false;
        localStorage.removeItem('personal_details_redirect');
    };

    return {
        onLoad,
        onUnload,

        setIsForNewAccount: (bool) => { is_for_new_account = bool; },
    };
})();

module.exports = PersonalDetails;
<commit_msg>fix check<commit_after>const SelectMatcher    = require('@binary-com/binary-style').select2Matcher;
const moment           = require('moment');
const BinaryPjax       = require('../../../../base/binary_pjax');
const Client           = require('../../../../base/client');
const Header           = require('../../../../base/header');
const BinarySocket     = require('../../../../base/socket');
const formatMoney      = require('../../../../common/currency').formatMoney;
const FormManager      = require('../../../../common/form_manager');
const Geocoder         = require('../../../../../_common/geocoder');
const CommonFunctions  = require('../../../../../_common/common_functions');
const localize         = require('../../../../../_common/localize').localize;
const State            = require('../../../../../_common/storage').State;
const getPropertyValue = require('../../../../../_common/utility').getPropertyValue;

const PersonalDetails = (() => {
    const form_id           = '#frmPersonalDetails';
    const real_acc_elements = '.RealAcc';

    let is_for_new_account = false;

    let editable_fields,
        is_virtual,
        residence,
        get_settings_data,
        currency;

    const init = () => {
        editable_fields   = {};
        get_settings_data = {};
        is_virtual        = Client.get('is_virtual');
        residence         = Client.get('residence');
    };

    const showHideTaxMessage = () => {
        const $tax_info_declaration = $('#tax_information_declaration');
        const $tax_information_info = $('#tax_information_info');

        if (Client.shouldCompleteTax()) {
            $('#tax_information_note_toggle').off('click').on('click', (e) => {
                e.stopPropagation();
                $('#tax_information_note_toggle').toggleClass('open');
                $('#tax_information_note').slideToggle();
            });
        } else {
            $tax_information_info.setVisibility(0); // hide tax info
            $tax_info_declaration.setVisibility(0); // hide tax info declaration
        }
    };

    const showHideLabel = (get_settings) => {
        ['place_of_birth', 'account_opening_reason', 'citizen'].forEach((id) => {
            if (Object.prototype.hasOwnProperty.call(get_settings, id)) {
                if (get_settings[id]) {
                    // we have to show text here instead of relying on displayGetSettingsData()
                    // since it prioritizes showing data instead of label
                    const $label = $(`#lbl_${id}`);
                    $label.text(get_settings[id]);
                    $(`#row_${id}`).setVisibility(0);
                    $(`#row_lbl_${id}`).setVisibility(1);
                } else {
                    $(`#row_lbl_${id}`).setVisibility(0);
                    $(`#row_${id}`).setVisibility(1);
                }
            }
        });
    };

    const showHideMissingDetails = () => {
        const validations = getValidations();
        const has_missing_field = validations.find((validation) => /req/.test(validation.validations) && $(validation.selector).val() === '');
        $('#missing_details_notice').setVisibility(!!has_missing_field);
    };

    const getDetailsResponse = (data, residence_list = State.getResponse('residence_list')) => {
        const get_settings         = $.extend({}, data);
        get_settings.date_of_birth = 'date_of_birth' in get_settings ? moment.utc(new Date(get_settings.date_of_birth * 1000)).format('YYYY-MM-DD') : '';
        const accounts             = Client.getAllLoginids();
        // for subaccounts, back-end sends loginid of the master account as name
        const hide_name            = accounts.some(loginid => new RegExp(loginid, 'i').test(get_settings.first_name)) || is_virtual;
        if (!hide_name) {
            get_settings.name = `${(get_settings.salutation || '')} ${(get_settings.first_name || '')} ${(get_settings.last_name || '')}`;
        }

        if (get_settings.place_of_birth) {
            get_settings.place_of_birth =
                (residence_list.find(obj => obj.value === get_settings.place_of_birth) || {}).text ||
                get_settings.place_of_birth;
        }

        if (get_settings.citizen) {
            get_settings.citizen =
                (residence_list.find(obj => obj.value === get_settings.citizen) || {}).text ||
                get_settings.citizen;
        }

        showHideLabel(get_settings);

        displayGetSettingsData(get_settings);

        if (is_virtual) {
            $(real_acc_elements).remove();
        } else {
            $(real_acc_elements).setVisibility(1);
            showHideTaxMessage();
        }
        $(form_id).setVisibility(1);
        $('#loading').remove();
        FormManager.init(form_id, getValidations());
        FormManager.handleSubmit({
            form_selector       : form_id,
            obj_request         : { set_settings: 1 },
            fnc_response_handler: setDetailsResponse,
            fnc_additional_check: additionalCheck,
            enable_button       : true,
        });
        if (!is_virtual) {
            Geocoder.validate(form_id);
        }
        showHideMissingDetails();
    };

    const displayGetSettingsData = (data, populate = true) => {
        let el_key,
            data_key;
        Object.keys(data).forEach((key) => {
            el_key = document.getElementById(key) || document.getElementById(`lbl_${key}`);
            if (el_key) {
                data_key             = /format_money/.test(el_key.className) && data[key] !== null ? formatMoney(currency, data[key]) : (data[key] || '');
                editable_fields[key] = data_key;
                if (populate) {
                    if (el_key.type === 'checkbox') {
                        el_key.checked = !!data_key;
                    } else if (/select|text/i.test(el_key.type)) {
                        $(el_key)
                            .val(data_key.split(','))
                            .trigger('change');
                    } else if (key !== 'country') {
                        CommonFunctions.elementInnerHtml(el_key, data_key ? localize(data_key) : '-');
                    }
                }
            }
        });
        if (data.country) {
            $('#residence').replaceWith($('<label/>').append($('<strong/>', { id: 'lbl_country' })));
            $('#lbl_country').text(data.country);
        }
    };

    const additionalCheck = (data) => {
        if (!isChanged(data)) {
            showFormMessage('You did not change anything.', false);
            return false;
        }
        return true;
    };

    const isChanged = (data) => {
        const compare_data = $.extend({}, data);
        return Object.keys(compare_data).some(key => (
            key !== 'set_settings' && editable_fields[key] !== compare_data[key]
        ));
    };

    const getValidations = () => {
        let validations;
        if (is_virtual) {
            validations = [
                { selector: '#email_consent' },
                { selector: '#residence', validations: ['req'] },
            ];
        } else {
            const is_financial      = Client.isAccountOfType('financial');
            const is_gaming         = Client.isAccountOfType('gaming');
            const mt_acct_type      = localStorage.getItem('personal_details_redirect');
            const is_for_mt_citizen = !!mt_acct_type;                                                   // all mt account opening requires citizen
            const is_for_mt_tax     = /real/.test(mt_acct_type) && mt_acct_type.split('_').length > 2;  // demo and volatility mt accounts do not require tax info
            const is_tax_req        = is_financial || (is_for_mt_tax && +State.getResponse('landing_company.config.tax_details_required') === 1);

            validations = [
                { selector: '#address_line_1',         validations: ['req', 'address'] },
                { selector: '#address_line_2',         validations: ['address'] },
                { selector: '#address_city',           validations: ['req', 'letter_symbol'] },
                { selector: '#address_state',          validations: $('#address_state').prop('nodeName') === 'SELECT' ? '' : ['letter_symbol'] },
                { selector: '#address_postcode',       validations: [Client.get('residence') === 'gb' ? 'req' : '', 'postcode', ['length', { min: 0, max: 20 }]] },
                { selector: '#email_consent' },
                { selector: '#phone',                  validations: ['req', 'phone', ['length', { min: 6, max: 35, value: () => $('#phone').val().replace(/^\+/, '')  }]] },
                { selector: '#place_of_birth',         validations: ['req'] },
                { selector: '#account_opening_reason', validations: ['req'] },

                { selector: '#tax_residence',  validations: (is_tax_req) ? ['req'] : '' },
                { selector: '#citizen',        validations: (is_financial || is_gaming || is_for_mt_citizen) ? ['req'] : '' },
                { selector: '#chk_tax_id',     validations: is_financial ? [['req', { hide_asterisk: true, message: localize('Please confirm that all the information above is true and complete.') }]] : '', exclude_request: 1 },
            ];

            const tax_id_validation  = { selector: '#tax_identification_number', validations: ['tax_id', ['length', { min: 0, max: 20 }]] };
            if (is_tax_req) {
                tax_id_validation.validations[1][1].min = 1;
                tax_id_validation.validations.unshift('req');
            }
            validations.push(tax_id_validation);
        }
        return validations;
    };

    const setDetailsResponse = (response) => {
        // allow user to resubmit the form on error.
        const is_error = response.set_settings !== 1;
        if (!is_error) {
            const redirect_url = localStorage.getItem('personal_details_redirect');
            // to update tax information message for financial clients
            BinarySocket.send({ get_account_status: 1 }, { forced: true }).then((response_status) => {
                showHideTaxMessage();
                Header.displayAccountStatus();
                if (redirect_url && +response_status.get_account_status.prompt_client_to_authenticate && Client.isAccountOfType('financial')) {
                    $('#msg_authenticate').setVisibility(1);
                }
            });
            // to update the State with latest get_settings data
            BinarySocket.send({ get_settings: 1 }, { forced: true }).then((data) => {
                if (is_virtual && response.echo_req.residence) {
                    window.location.reload(); // reload page if we are setting residence
                    return;
                }
                // update notification shown for set residence etc
                Header.displayAccountStatus();
                if (is_for_new_account) {
                    is_for_new_account = false;
                    BinaryPjax.loadPreviousUrl();
                    return;
                }
                const get_settings    = data.get_settings;
                const has_required_mt = (+State.getResponse('landing_company.config.tax_details_required') === 1 ?
                    (get_settings.tax_residence && get_settings.tax_identification_number && get_settings.citizen)
                    :
                    get_settings.citizen // only check Citizen if tax details are not required
                );
                if (redirect_url && has_required_mt) {
                    localStorage.removeItem('personal_details_redirect');
                    $.scrollTo($('h1#heading'), 500, { offset: -10 });
                    $(form_id).setVisibility(0);
                    $('#missing_details_notice').setVisibility(0);
                    $('.rowCustomerSupport').setVisibility(0);
                    $('#msg_main').setVisibility(1);
                    return;
                }
                getDetailsResponse(get_settings);
            });
        }
        showFormMessage(is_error ?
            (getPropertyValue(response, ['error', 'message']) || 'Sorry, an error occurred while processing your account.') :
            'Your settings have been updated successfully.', !is_error);
    };

    const showFormMessage = (msg, is_success) => {
        $('#formMessage')
            .attr('class', is_success ? 'success-msg' : 'errorfield')
            .html(is_success ? $('<ul/>', { class: 'checked' }).append($('<li/>', { text: localize(msg) })) : localize(msg))
            .css('display', 'block')
            .delay(5000)
            .fadeOut(1000);
    };

    const populateResidence = (response) => (
        new Promise((resolve) => {
            const residence_list = response.residence_list;
            if (residence_list.length > 0) {
                const $options               = $('<div/>');
                const $options_with_disabled = $('<div/>');
                residence_list.forEach((res) => {
                    $options.append(CommonFunctions.makeOption({ text: res.text, value: res.value }));
                    $options_with_disabled.append(CommonFunctions.makeOption({
                        text       : res.text,
                        value      : res.value,
                        is_disabled: res.disabled,
                    }));
                });

                if (residence) {
                    const $tax_residence = $('#tax_residence');
                    $tax_residence.html($options_with_disabled.html()).promise().done(() => {
                        setTimeout(() => {
                            $tax_residence.select2()
                                .val(get_settings_data.tax_residence ? get_settings_data.tax_residence.split(',') : '')
                                .trigger('change')
                                .setVisibility(1);
                        }, 500);
                    });

                    if (!get_settings_data.place_of_birth) {
                        $options.prepend($('<option/>', { value: '', text: localize('Please select') }));
                        $('#place_of_birth')
                            .html($options.html())
                            .val(residence);
                    }

                    if (!get_settings_data.citizen) {
                        $options.prepend($('<option/>', { value: '', text: localize('Please select') }));
                        $('#citizen')
                            .html($options.html())
                            .val(residence);
                    }
                } else {
                    $('#lbl_country').parent().replaceWith($('<select/>', { id: 'residence', single: 'single' }));
                    const $residence = $('#residence');
                    $options_with_disabled.prepend($('<option/>', { text: localize('Please select a country'), value: '' }));
                    $residence.html($options_with_disabled.html());
                    $residence.select2({
                        matcher(params, data) {
                            return SelectMatcher(params, data);
                        },
                    });
                }
            }
            resolve();
        })
    );

    const populateStates = (response) => (
        new Promise((resolve) => {
            const states = response.states_list;

            const address_state = '#address_state';
            let $field          = $(address_state);

            $field.empty();

            if (states && states.length > 0) {
                $field.append($('<option/>', { value: '', text: localize('Please select') }));
                states.forEach((state) => {
                    $field.append($('<option/>', { value: state.value, text: state.text }));
                });
            } else {
                $field.replaceWith($('<input/>', { id: address_state.replace('#', ''), name: 'address_state', type: 'text', maxlength: '35', 'data-lpignore': true }));
                $field = $(address_state);
            }
            $field.val(get_settings_data.address_state);

            if (states && states.length > 0) {
                $('#address_state').select2({
                    matcher(params, data) {
                        return SelectMatcher(params, data);
                    },
                });
            }
            $field.val(get_settings_data.address_state);

            resolve();
        })
    );

    const onLoad = () => {
        currency = Client.get('currency');
        BinarySocket.wait('get_account_status', 'get_settings', 'landing_company').then(() => {
            init();
            get_settings_data = State.getResponse('get_settings');

            if (is_virtual) {
                getDetailsResponse(get_settings_data);
            }

            if (!is_virtual || !residence) {
                BinarySocket.send({ residence_list: 1 }).then(response => {
                    populateResidence(response).then(() => {
                        if (residence) {
                            BinarySocket.send({ states_list: residence }).then(response_state => {
                                populateStates(response_state).then(() => {
                                    getDetailsResponse(get_settings_data, response.residence_list);
                                });
                            });
                        } else {
                            getDetailsResponse(get_settings_data, response.residence_list);
                        }
                        $('#place_of_birth, #citizen').select2({
                            matcher(params, data) {
                                return SelectMatcher(params, data);
                            },
                        });
                    });
                });
            }
        });
    };

    const onUnload = () => {
        is_for_new_account = false;
        localStorage.removeItem('personal_details_redirect');
    };

    return {
        onLoad,
        onUnload,

        setIsForNewAccount: (bool) => { is_for_new_account = bool; },
    };
})();

module.exports = PersonalDetails;
<|endoftext|>


<commit_before>const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const npmSass = require('npm-sass');
const autoprefixer = require('autoprefixer');
const postcssDiscardDuplicates = require('postcss-discard-duplicates');
const ManifestPlugin = require('webpack-manifest-plugin');
const sassImportGlobbing = require('@theme-tools/sass-import-globbing');
const assets = require('./utils/assets');

function createConfig(config) {
  // @TODO: move this setting to .boltrc config
  const sassExportData = require('@theme-tools/sass-export-data')({
    path: path.resolve(process.cwd(), config.dataDir),
  });

  // Map out the global config verbosity setting to the 6 preset levels of Webpack stats: https://webpack.js.org/configuration/stats/#stats + https://github.com/webpack/webpack/blob/b059e07cf90db871fe9497f5c14b9383fc71d2ad/lib/Stats.js#L906

  const webpackStats = {
    0: 'none', // Output nothing
    1: 'errors-only', // only output when errors happen
    2: 'minimal', // only output when errors or new compilation happen
    3: 'normal', // standard output
    4: 'detailed',
    5: 'verbose', // output everything
  };

  function statsPreset(name) {
    /**
     * Accepted values: none, errors-only, minimal, normal, detailed,
     * verbose. Any other falsy value will behave as 'none', truthy
     * values as 'normal'
     */
    const pn = (typeof name === "string") && name.toLowerCase() || name || "none";

    switch (pn) {
      case 'none':
        return {
          all: false
        };
      case 'verbose':
        return {
          entrypoints: true,
          modules: false,
          colors: true,
          chunks: true,
          chunkModules: true,
          chunkOrigins: true,
          depth: true,
          env: true,
          reasons: true,
          usedExports: true,
          providedExports: true,
          optimizationBailout: true,
          errorDetails: true,
          publicPath: true,
          exclude: () => false,
          maxModules: Infinity,
        };
      case 'detailed':
        return {
          entrypoints: true,
          chunks: true,
          colors: true,
          chunkModules: false,
          chunkOrigins: true,
          depth: true,
          usedExports: true,
          providedExports: true,
          optimizationBailout: true,
          errorDetails: true,
          publicPath: true,
          exclude: () => false,
          maxModules: Infinity,
        };
      case 'minimal':
        return {
          all: false,
          colors: true,
          modules: true,
          maxModules: 0,
          errors: true,
          warnings: true,
        };
      case 'errors-only':
        return {
          all: false,
          colors: true,
          errors: true,
          moduleTrace: true,
        };
      default:
        return {
          colors: true
        }
    }
  }

  const scssLoaders = [
    {
      loader: 'css-loader',
      options: {
        sourceMap: true,
        modules: true,
        importLoaders: true,
        localIdentName: '[local]'
      }
    },
    {
      loader: "postcss-loader",
      options: {
        plugins: [
          postcssDiscardDuplicates,
          autoprefixer,
        ],
      }
    },
    {
      loader: "clean-css-loader",
      options: {
        skipWarn: true,
        compatibility: "ie9",
        level: process.env.NODE_ENV === "production" ? 2 : 0,
        inline: ["remote"],
        format: 'beautify',
      }
    },
    {
      loader: "sass-loader",
      options: {
        importer: [
          sassImportGlobbing,
          npmSass.importer,
        ],
        functions: sassExportData,
        outputStyle: "expanded",
        precision: 2
      }
    }
  ];

  // The publicPath config sets the client-side base path for all built / asynchronously loaded assets. By default the loader script will automatically figure out the relative path to load your components, but uses publicPath as a fallback. It's recommended to have it start with a `/`. Note: this ONLY sets the base path the browser requests -- it does not set where files are saved during build. To change where files are saved at build time, use the buildDir config.
  // Must start and end with `/`
  const publicPath = `/${path.relative(config.wwwDir, config.buildDir)}/`;

  return {
    entry: assets.buildWebpackEntry(config.components),
    output: {
      path: path.resolve(process.cwd(), config.buildDir),
      filename: "[name].js",
      publicPath: publicPath,
    },
    devtool: 'cheap-module-eval-source-map',
    resolve: {
      extensions: [".js", ".jsx", ".json", ".svg", ".scss"]
    },
    module: {
      rules: [
        {
          test: /\.scss$/,
          oneOf: [
            {
              issuer: /\.js$/,
              use: scssLoaders,
            },
            {
              // no issuer here as it has a bug when its an entry point - https://github.com/webpack/webpack/issues/5906
              use: ExtractTextPlugin.extract({
                fallback: "style-loader",
                use: scssLoaders,
              })
            },
          ],
        },
        {
          test: /\.js$/,
          exclude: /(node_modules\/\@webcomponents\/webcomponentsjs\/custom-elements-es5-adapter\.js)/,
          use: {
            loader: 'babel-loader',
            options: {
              babelrc: false,
              presets: ['@bolt/babel-preset-bolt'],
            }
          }
        },
      ],
    },
    plugins: [
      // Ignore generated output if generated output is on a dependency chain (causes endless loop)
      new webpack.WatchIgnorePlugin([
        /dist\/styleguide/,
        /dist\/annotations/,
        /styleguide/,
        path.join(__dirname, 'node_modules')
      ]),
      new webpack.HotModuleReplacementPlugin(),
      new webpack.optimize.CommonsChunkPlugin({
        deepChildren: true,
        children: true,
        minChunks: Infinity,
        async: true
      }),
      new webpack.IgnorePlugin(/vertx/), // needed to ignore vertx dependency in webcomponentsjs-lite
      new ExtractTextPlugin({
        filename: "[name].css",
        // disable: false,
        allChunks: true
      }),
      // @todo This needs to be in `config.dataDir`
      new ManifestPlugin({
        fileName: 'bolt-webpack-manifest.json',
        publicPath: publicPath,
        writeToFileEmit: true,
        seed: {
          name: 'Bolt Manifest'
        }
      }),
      new webpack.optimize.ModuleConcatenationPlugin(),
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': process.env.NODE_ENV === 'production' ? JSON.stringify(process.env.NODE_ENV) : JSON.stringify('development'),
      }),
      new webpack.ProvidePlugin({
        h: 'preact',
        Promise: 'es6-promise'
      }),
      // Show build progress
      // Disabling for now as it messes up spinners
      // @todo consider bringing it back
      // new webpack.ProgressPlugin({ profile: false }),
    ],
    devServer: {
      contentBase: [
        path.resolve(process.cwd(), config.wwwDir),
        // @TODO: add Pattern Lab Styleguidekit Assets Default dist path here
      ],
      compress: true,
      clientLogLevel: 'none',
      port: 8080,
      stats: statsPreset(webpackStats[config.verbosity]),
      overlay: {
        errors: true
      },
      hot: true,
      inline: true,
      noInfo: true, // webpackTasks.watch handles output info related to success & failure
      publicPath: publicPath,
      watchContentBase: true,
      historyApiFallback: true,
      watchOptions: {
        aggregateTimeout: 500,
        // ignored: /(annotations|fonts|bower_components|dist\/styleguide|node_modules|styleguide|images|fonts|assets)/
        // Poll using interval (in ms, accepts boolean too)
        poll: true,
      }
    }
  };
}

module.exports = createConfig;
<commit_msg>Slight tweak to WebPack config to set it up for conditional adjustments<commit_after>const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const npmSass = require('npm-sass');
const autoprefixer = require('autoprefixer');
const postcssDiscardDuplicates = require('postcss-discard-duplicates');
const ManifestPlugin = require('webpack-manifest-plugin');
const sassImportGlobbing = require('@theme-tools/sass-import-globbing');
const assets = require('./utils/assets');

function createConfig(config) {
  // @TODO: move this setting to .boltrc config
  const sassExportData = require('@theme-tools/sass-export-data')({
    path: path.resolve(process.cwd(), config.dataDir),
  });

  // Map out the global config verbosity setting to the 6 preset levels of Webpack stats: https://webpack.js.org/configuration/stats/#stats + https://github.com/webpack/webpack/blob/b059e07cf90db871fe9497f5c14b9383fc71d2ad/lib/Stats.js#L906

  const webpackStats = {
    0: 'none', // Output nothing
    1: 'errors-only', // only output when errors happen
    2: 'minimal', // only output when errors or new compilation happen
    3: 'normal', // standard output
    4: 'detailed',
    5: 'verbose', // output everything
  };

  function statsPreset(name) {
    /**
     * Accepted values: none, errors-only, minimal, normal, detailed,
     * verbose. Any other falsy value will behave as 'none', truthy
     * values as 'normal'
     */
    const pn = (typeof name === "string") && name.toLowerCase() || name || "none";

    switch (pn) {
      case 'none':
        return {
          all: false
        };
      case 'verbose':
        return {
          entrypoints: true,
          modules: false,
          colors: true,
          chunks: true,
          chunkModules: true,
          chunkOrigins: true,
          depth: true,
          env: true,
          reasons: true,
          usedExports: true,
          providedExports: true,
          optimizationBailout: true,
          errorDetails: true,
          publicPath: true,
          exclude: () => false,
          maxModules: Infinity,
        };
      case 'detailed':
        return {
          entrypoints: true,
          chunks: true,
          colors: true,
          chunkModules: false,
          chunkOrigins: true,
          depth: true,
          usedExports: true,
          providedExports: true,
          optimizationBailout: true,
          errorDetails: true,
          publicPath: true,
          exclude: () => false,
          maxModules: Infinity,
        };
      case 'minimal':
        return {
          all: false,
          colors: true,
          modules: true,
          maxModules: 0,
          errors: true,
          warnings: true,
        };
      case 'errors-only':
        return {
          all: false,
          colors: true,
          errors: true,
          moduleTrace: true,
        };
      default:
        return {
          colors: true
        }
    }
  }

  const scssLoaders = [
    {
      loader: 'css-loader',
      options: {
        sourceMap: true,
        modules: true,
        importLoaders: true,
        localIdentName: '[local]'
      }
    },
    {
      loader: "postcss-loader",
      options: {
        plugins: [
          postcssDiscardDuplicates,
          autoprefixer,
        ],
      }
    },
    {
      loader: "clean-css-loader",
      options: {
        skipWarn: true,
        compatibility: "ie9",
        level: process.env.NODE_ENV === "production" ? 2 : 0,
        inline: ["remote"],
        format: 'beautify',
      }
    },
    {
      loader: "sass-loader",
      options: {
        importer: [
          sassImportGlobbing,
          npmSass.importer,
        ],
        functions: sassExportData,
        outputStyle: "expanded",
        precision: 2
      }
    }
  ];

  // The publicPath config sets the client-side base path for all built / asynchronously loaded assets. By default the loader script will automatically figure out the relative path to load your components, but uses publicPath as a fallback. It's recommended to have it start with a `/`. Note: this ONLY sets the base path the browser requests -- it does not set where files are saved during build. To change where files are saved at build time, use the buildDir config.
  // Must start and end with `/`
  const publicPath = `/${path.relative(config.wwwDir, config.buildDir)}/`;

  // THIS IS IT!! The object that gets passed in as WebPack's config object.
  const webpackConfig = {
    entry: assets.buildWebpackEntry(config.components),
    output: {
      path: path.resolve(process.cwd(), config.buildDir),
      filename: "[name].js",
      publicPath: publicPath,
    },
    devtool: 'cheap-module-eval-source-map',
    resolve: {
      extensions: [".js", ".jsx", ".json", ".svg", ".scss"]
    },
    module: {
      rules: [
        {
          test: /\.scss$/,
          oneOf: [
            {
              issuer: /\.js$/,
              use: scssLoaders,
            },
            {
              // no issuer here as it has a bug when its an entry point - https://github.com/webpack/webpack/issues/5906
              use: ExtractTextPlugin.extract({
                fallback: "style-loader",
                use: scssLoaders,
              })
            },
          ],
        },
        {
          test: /\.js$/,
          exclude: /(node_modules\/\@webcomponents\/webcomponentsjs\/custom-elements-es5-adapter\.js)/,
          use: {
            loader: 'babel-loader',
            options: {
              babelrc: false,
              presets: ['@bolt/babel-preset-bolt'],
            }
          }
        },
      ],
    },
    plugins: [
      // Ignore generated output if generated output is on a dependency chain (causes endless loop)
      new webpack.WatchIgnorePlugin([
        /dist\/styleguide/,
        /dist\/annotations/,
        /styleguide/,
        path.join(__dirname, 'node_modules')
      ]),
      new webpack.HotModuleReplacementPlugin(),
      new webpack.optimize.CommonsChunkPlugin({
        deepChildren: true,
        children: true,
        minChunks: Infinity,
        async: true
      }),
      new webpack.IgnorePlugin(/vertx/), // needed to ignore vertx dependency in webcomponentsjs-lite
      new ExtractTextPlugin({
        filename: "[name].css",
        // disable: false,
        allChunks: true
      }),
      // @todo This needs to be in `config.dataDir`
      new ManifestPlugin({
        fileName: 'bolt-webpack-manifest.json',
        publicPath: publicPath,
        writeToFileEmit: true,
        seed: {
          name: 'Bolt Manifest'
        }
      }),
      new webpack.optimize.ModuleConcatenationPlugin(),
      new webpack.DefinePlugin({
        'process.env.NODE_ENV': process.env.NODE_ENV === 'production' ? JSON.stringify(process.env.NODE_ENV) : JSON.stringify('development'),
      }),
      new webpack.ProvidePlugin({
        h: 'preact',
        Promise: 'es6-promise'
      }),
      // Show build progress
      // Disabling for now as it messes up spinners
      // @todo consider bringing it back
      // new webpack.ProgressPlugin({ profile: false }),
    ],
    devServer: {
      contentBase: [
        path.resolve(process.cwd(), config.wwwDir),
        // @TODO: add Pattern Lab Styleguidekit Assets Default dist path here
      ],
      compress: true,
      clientLogLevel: 'none',
      port: 8080,
      stats: statsPreset(webpackStats[config.verbosity]),
      overlay: {
        errors: true
      },
      hot: true,
      inline: true,
      noInfo: true, // webpackTasks.watch handles output info related to success & failure
      publicPath: publicPath,
      watchContentBase: true,
      historyApiFallback: true,
      watchOptions: {
        aggregateTimeout: 500,
        // ignored: /(annotations|fonts|bower_components|dist\/styleguide|node_modules|styleguide|images|fonts|assets)/
        // Poll using interval (in ms, accepts boolean too)
        poll: true,
      }
    }
  };

  return webpackConfig;
}

module.exports = createConfig;
<|endoftext|>