// // SertifikatNewCell.swift // Sirani // // Created by Hendi on 19/06/23. // Copyright © 2026 PT. Mitra Sinerji Teknoindo. All rights reserved. // import UIKit import MaterialComponents.MaterialCards protocol SertifikatNewCellDelegate: NSObjectProtocol { func openSertifikatDetail(data: CertificateData?) } class SertifikatNewCell: UITableViewCell { @IBOutlet weak var card: MDCCard! @IBOutlet weak var lblNomor: UILabel! @IBOutlet weak var lblPemohon: UILabel! @IBOutlet weak var lblPerangkat: UILabel! @IBOutlet weak var lblMerk: UILabel! @IBOutlet weak var lblModel: UILabel! @IBOutlet weak var lblBrand: UILabel! @IBOutlet weak var lblBerlakuDate: UILabel! @IBOutlet weak var lblBerakhirDate: UILabel! @IBOutlet weak var lblStatus: UILabel! @IBOutlet weak var lblNegara: UILabel! var cellDelegate: SertifikatNewCellDelegate? var dataSertifikat: CertificateData? // Modern UI Elements private let modernContainer = UIView() private let modernBadgeView = UIView() private let modernBadgeIcon = UIImageView() private let modernNomorLabel = UILabel() private let modernCategoryLabel = UILabel() private let modernStatusPill = UIView() private let modernStatusLabel = UILabel() private let modernPerangkatLabel = UILabel() private let modernCompanyIcon = UIImageView() private let modernPemohonLabel = UILabel() private let modernSpecStack = UIStackView() private let modernMerkCard = UIView() private let modernMerkTitle = UILabel() private let modernMerkVal = UILabel() private let modernNegaraCard = UIView() private let modernNegaraTitle = UILabel() private let modernNegaraVal = UILabel() private let modernValidityCard = UIView() private let modernCalendarIcon = UIImageView() private let modernValidityLabel = UILabel() private let modernDetailLabel = UILabel() private let modernChevronIcon = UIImageView() private var isModernLayoutBuilt = false override func awakeFromNib() { super.awakeFromNib() self.selectionStyle = .none self.backgroundColor = .clear setupCardVisuals() setupModernLayout() } private func setupCardVisuals() { guard let card = card else { return } card.cornerRadius = 16 card.setShadowElevation(ShadowElevation(rawValue: 2), for: .normal) card.setShadowColor(UIColor.black.withAlphaComponent(0.06), for: .normal) card.layer.borderColor = UIColor(red: 228/255, green: 235/255, blue: 245/255, alpha: 1.0).cgColor card.layer.borderWidth = 1.0 card.backgroundColor = .white } private func setupModernLayout() { guard let card = card, !isModernLayoutBuilt else { return } isModernLayoutBuilt = true // Hide legacy storyboard labels for subview in card.subviews { subview.isHidden = true } modernContainer.translatesAutoresizingMaskIntoConstraints = false modernContainer.backgroundColor = .clear card.addSubview(modernContainer) NSLayoutConstraint.activate([ modernContainer.topAnchor.constraint(equalTo: card.topAnchor, constant: 14), modernContainer.bottomAnchor.constraint(equalTo: card.bottomAnchor, constant: -14), modernContainer.leadingAnchor.constraint(equalTo: card.leadingAnchor, constant: 14), modernContainer.trailingAnchor.constraint(equalTo: card.trailingAnchor, constant: -14) ]) // 1. Header Bar let headerStack = UIStackView() headerStack.translatesAutoresizingMaskIntoConstraints = false headerStack.axis = .horizontal headerStack.alignment = .center headerStack.spacing = 10 modernContainer.addSubview(headerStack) // Badge Icon Box modernBadgeView.translatesAutoresizingMaskIntoConstraints = false modernBadgeView.backgroundColor = UIColor(red: 235/255, green: 242/255, blue: 252/255, alpha: 1.0) modernBadgeView.layer.cornerRadius = 8 modernBadgeView.layer.masksToBounds = true modernBadgeIcon.translatesAutoresizingMaskIntoConstraints = false if #available(iOS 13.0, *) { modernBadgeIcon.image = UIImage(systemName: "checkmark.seal.fill") } modernBadgeIcon.tintColor = UIColor.siraniPrimaryBlue modernBadgeIcon.contentMode = .scaleAspectFit modernBadgeView.addSubview(modernBadgeIcon) NSLayoutConstraint.activate([ modernBadgeView.widthAnchor.constraint(equalToConstant: 32), modernBadgeView.heightAnchor.constraint(equalToConstant: 32), modernBadgeIcon.centerXAnchor.constraint(equalTo: modernBadgeView.centerXAnchor), modernBadgeIcon.centerYAnchor.constraint(equalTo: modernBadgeView.centerYAnchor), modernBadgeIcon.widthAnchor.constraint(equalToConstant: 18), modernBadgeIcon.heightAnchor.constraint(equalToConstant: 18) ]) headerStack.addArrangedSubview(modernBadgeView) // Title & Number Stack let numberStack = UIStackView() numberStack.axis = .vertical numberStack.spacing = 1 modernCategoryLabel.font = UIFont.systemFont(ofSize: 9, weight: .bold) modernCategoryLabel.textColor = UIColor(red: 140/255, green: 155/255, blue: 175/255, alpha: 1.0) modernCategoryLabel.text = "NOMOR SERTIFIKAT" numberStack.addArrangedSubview(modernCategoryLabel) modernNomorLabel.font = UIFont.systemFont(ofSize: 14, weight: .bold) modernNomorLabel.textColor = UIColor.siraniPrimaryBlue modernNomorLabel.numberOfLines = 1 modernNomorLabel.setContentHuggingPriority(.defaultLow, for: .horizontal) modernNomorLabel.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) numberStack.addArrangedSubview(modernNomorLabel) headerStack.addArrangedSubview(numberStack) // Status Pill Badge modernStatusPill.translatesAutoresizingMaskIntoConstraints = false modernStatusPill.layer.cornerRadius = 6 modernStatusPill.layer.masksToBounds = true modernStatusPill.backgroundColor = UIColor(red: 230/255, green: 244/255, blue: 234/255, alpha: 1.0) modernStatusLabel.translatesAutoresizingMaskIntoConstraints = false modernStatusLabel.font = UIFont.systemFont(ofSize: 10, weight: .bold) modernStatusLabel.textColor = UIColor(red: 19/255, green: 115/255, blue: 51/255, alpha: 1.0) modernStatusLabel.textAlignment = .center modernStatusPill.addSubview(modernStatusLabel) NSLayoutConstraint.activate([ modernStatusLabel.topAnchor.constraint(equalTo: modernStatusPill.topAnchor, constant: 4), modernStatusLabel.bottomAnchor.constraint(equalTo: modernStatusPill.bottomAnchor, constant: -4), modernStatusLabel.leadingAnchor.constraint(equalTo: modernStatusPill.leadingAnchor, constant: 8), modernStatusLabel.trailingAnchor.constraint(equalTo: modernStatusPill.trailingAnchor, constant: -8) ]) headerStack.addArrangedSubview(modernStatusPill) // 2. Divider Line let divider = UIView() divider.translatesAutoresizingMaskIntoConstraints = false divider.backgroundColor = UIColor(red: 240/255, green: 244/255, blue: 250/255, alpha: 1.0) modernContainer.addSubview(divider) // 3. Equipment Name (Headline) modernPerangkatLabel.translatesAutoresizingMaskIntoConstraints = false modernPerangkatLabel.font = UIFont.systemFont(ofSize: 15, weight: .bold) modernPerangkatLabel.textColor = UIColor(red: 26/255, green: 29/255, blue: 38/255, alpha: 1.0) modernPerangkatLabel.numberOfLines = 2 modernContainer.addSubview(modernPerangkatLabel) // 4. Company Name Row let companyStack = UIStackView() companyStack.translatesAutoresizingMaskIntoConstraints = false companyStack.axis = .horizontal companyStack.spacing = 6 companyStack.alignment = .center if #available(iOS 13.0, *) { modernCompanyIcon.image = UIImage(systemName: "building.2.fill") } modernCompanyIcon.tintColor = UIColor(red: 120/255, green: 135/255, blue: 155/255, alpha: 1.0) modernCompanyIcon.contentMode = .scaleAspectFit modernCompanyIcon.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ modernCompanyIcon.widthAnchor.constraint(equalToConstant: 14), modernCompanyIcon.heightAnchor.constraint(equalToConstant: 14) ]) companyStack.addArrangedSubview(modernCompanyIcon) modernPemohonLabel.font = UIFont.systemFont(ofSize: 12, weight: .semibold) modernPemohonLabel.textColor = UIColor(red: 90/255, green: 105/255, blue: 125/255, alpha: 1.0) modernPemohonLabel.numberOfLines = 1 companyStack.addArrangedSubview(modernPemohonLabel) modernContainer.addSubview(companyStack) // 5. Spec Mini Cards (Merk & Model, Negara) modernSpecStack.translatesAutoresizingMaskIntoConstraints = false modernSpecStack.axis = .horizontal modernSpecStack.distribution = .fillEqually modernSpecStack.spacing = 8 modernContainer.addSubview(modernSpecStack) // Merk Card modernMerkCard.backgroundColor = UIColor(red: 248/255, green: 250/255, blue: 253/255, alpha: 1.0) modernMerkCard.layer.cornerRadius = 8 modernMerkCard.layer.borderWidth = 1 modernMerkCard.layer.borderColor = UIColor(red: 235/255, green: 240/255, blue: 248/255, alpha: 1.0).cgColor let merkInnerStack = UIStackView() merkInnerStack.translatesAutoresizingMaskIntoConstraints = false merkInnerStack.axis = .vertical merkInnerStack.spacing = 2 modernMerkCard.addSubview(merkInnerStack) modernMerkTitle.font = UIFont.systemFont(ofSize: 9, weight: .bold) modernMerkTitle.textColor = UIColor(red: 140/255, green: 155/255, blue: 175/255, alpha: 1.0) modernMerkTitle.text = "MERK & MODEL" merkInnerStack.addArrangedSubview(modernMerkTitle) modernMerkVal.font = UIFont.systemFont(ofSize: 11, weight: .semibold) modernMerkVal.textColor = UIColor(red: 40/255, green: 50/255, blue: 65/255, alpha: 1.0) modernMerkVal.numberOfLines = 1 merkInnerStack.addArrangedSubview(modernMerkVal) NSLayoutConstraint.activate([ merkInnerStack.topAnchor.constraint(equalTo: modernMerkCard.topAnchor, constant: 6), merkInnerStack.bottomAnchor.constraint(equalTo: modernMerkCard.bottomAnchor, constant: -6), merkInnerStack.leadingAnchor.constraint(equalTo: modernMerkCard.leadingAnchor, constant: 8), merkInnerStack.trailingAnchor.constraint(equalTo: modernMerkCard.trailingAnchor, constant: -8) ]) modernSpecStack.addArrangedSubview(modernMerkCard) // Negara Card modernNegaraCard.backgroundColor = UIColor(red: 248/255, green: 250/255, blue: 253/255, alpha: 1.0) modernNegaraCard.layer.cornerRadius = 8 modernNegaraCard.layer.borderWidth = 1 modernNegaraCard.layer.borderColor = UIColor(red: 235/255, green: 240/255, blue: 248/255, alpha: 1.0).cgColor let negaraInnerStack = UIStackView() negaraInnerStack.translatesAutoresizingMaskIntoConstraints = false negaraInnerStack.axis = .vertical negaraInnerStack.spacing = 2 modernNegaraCard.addSubview(negaraInnerStack) modernNegaraTitle.font = UIFont.systemFont(ofSize: 9, weight: .bold) modernNegaraTitle.textColor = UIColor(red: 140/255, green: 155/255, blue: 175/255, alpha: 1.0) modernNegaraTitle.text = "NEGARA ASAL" negaraInnerStack.addArrangedSubview(modernNegaraTitle) modernNegaraVal.font = UIFont.systemFont(ofSize: 11, weight: .semibold) modernNegaraVal.textColor = UIColor(red: 40/255, green: 50/255, blue: 65/255, alpha: 1.0) modernNegaraVal.numberOfLines = 1 negaraInnerStack.addArrangedSubview(modernNegaraVal) NSLayoutConstraint.activate([ negaraInnerStack.topAnchor.constraint(equalTo: modernNegaraCard.topAnchor, constant: 6), negaraInnerStack.bottomAnchor.constraint(equalTo: modernNegaraCard.bottomAnchor, constant: -6), negaraInnerStack.leadingAnchor.constraint(equalTo: modernNegaraCard.leadingAnchor, constant: 8), negaraInnerStack.trailingAnchor.constraint(equalTo: modernNegaraCard.trailingAnchor, constant: -8) ]) modernSpecStack.addArrangedSubview(modernNegaraCard) // 6. Validity Bar (Bottom Footer) modernValidityCard.translatesAutoresizingMaskIntoConstraints = false modernValidityCard.backgroundColor = UIColor(red: 244/255, green: 248/255, blue: 254/255, alpha: 1.0) modernValidityCard.layer.cornerRadius = 8 modernContainer.addSubview(modernValidityCard) let validityStack = UIStackView() validityStack.translatesAutoresizingMaskIntoConstraints = false validityStack.axis = .horizontal validityStack.alignment = .center validityStack.spacing = 6 modernValidityCard.addSubview(validityStack) if #available(iOS 13.0, *) { modernCalendarIcon.image = UIImage(systemName: "calendar") } modernCalendarIcon.tintColor = UIColor.siraniPrimaryBlue modernCalendarIcon.contentMode = .scaleAspectFit modernCalendarIcon.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ modernCalendarIcon.widthAnchor.constraint(equalToConstant: 13), modernCalendarIcon.heightAnchor.constraint(equalToConstant: 13) ]) validityStack.addArrangedSubview(modernCalendarIcon) modernValidityLabel.font = UIFont.systemFont(ofSize: 11, weight: .medium) modernValidityLabel.textColor = UIColor(red: 50/255, green: 70/255, blue: 95/255, alpha: 1.0) modernValidityLabel.numberOfLines = 1 validityStack.addArrangedSubview(modernValidityLabel) let spacer = UIView() spacer.setContentHuggingPriority(.defaultLow, for: .horizontal) validityStack.addArrangedSubview(spacer) modernDetailLabel.font = UIFont.systemFont(ofSize: 11, weight: .bold) modernDetailLabel.textColor = UIColor.siraniPrimaryBlue modernDetailLabel.text = "Detail" validityStack.addArrangedSubview(modernDetailLabel) if #available(iOS 13.0, *) { modernChevronIcon.image = UIImage(systemName: "chevron.right") } modernChevronIcon.tintColor = UIColor.siraniPrimaryBlue modernChevronIcon.contentMode = .scaleAspectFit modernChevronIcon.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activate([ modernChevronIcon.widthAnchor.constraint(equalToConstant: 10), modernChevronIcon.heightAnchor.constraint(equalToConstant: 10) ]) validityStack.addArrangedSubview(modernChevronIcon) NSLayoutConstraint.activate([ validityStack.topAnchor.constraint(equalTo: modernValidityCard.topAnchor, constant: 6), validityStack.bottomAnchor.constraint(equalTo: modernValidityCard.bottomAnchor, constant: -6), validityStack.leadingAnchor.constraint(equalTo: modernValidityCard.leadingAnchor, constant: 10), validityStack.trailingAnchor.constraint(equalTo: modernValidityCard.trailingAnchor, constant: -10) ]) // Main Container Constraints NSLayoutConstraint.activate([ headerStack.topAnchor.constraint(equalTo: modernContainer.topAnchor), headerStack.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor), headerStack.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor), divider.topAnchor.constraint(equalTo: headerStack.bottomAnchor, constant: 10), divider.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor), divider.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor), divider.heightAnchor.constraint(equalToConstant: 1), modernPerangkatLabel.topAnchor.constraint(equalTo: divider.bottomAnchor, constant: 10), modernPerangkatLabel.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor), modernPerangkatLabel.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor), companyStack.topAnchor.constraint(equalTo: modernPerangkatLabel.bottomAnchor, constant: 6), companyStack.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor), companyStack.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor), modernSpecStack.topAnchor.constraint(equalTo: companyStack.bottomAnchor, constant: 10), modernSpecStack.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor), modernSpecStack.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor), modernValidityCard.topAnchor.constraint(equalTo: modernSpecStack.bottomAnchor, constant: 10), modernValidityCard.leadingAnchor.constraint(equalTo: modernContainer.leadingAnchor), modernValidityCard.trailingAnchor.constraint(equalTo: modernContainer.trailingAnchor), modernValidityCard.bottomAnchor.constraint(equalTo: modernContainer.bottomAnchor) ]) } func updateViews(certificateData: CertificateData) { setupCardVisuals() setupModernLayout() card.isInteractable = true let gesture = UITapGestureRecognizer(target: self, action: #selector(self.onItemTap)) card.addGestureRecognizer(gesture) // 1. Nomor modernNomorLabel.text = certificateData.nomor.isEmpty ? "-" : certificateData.nomor // 2. Status Pill let statusStr = certificateData.statusBerlaku.trimmingCharacters(in: .whitespacesAndNewlines) let displayStatus = statusStr.isEmpty ? "TERBIT" : statusStr.uppercased() modernStatusLabel.text = displayStatus if displayStatus.contains("CABUT") || displayStatus.contains("TIDAK") { modernStatusPill.backgroundColor = UIColor(red: 254/255, green: 242/255, blue: 242/255, alpha: 1.0) modernStatusLabel.textColor = UIColor(red: 220/255, green: 38/255, blue: 38/255, alpha: 1.0) } else if displayStatus.contains("REVISI") || displayStatus.contains("PROSES") { modernStatusPill.backgroundColor = UIColor(red: 254/255, green: 249/255, blue: 235/255, alpha: 1.0) modernStatusLabel.textColor = UIColor(red: 180/255, green: 83/255, blue: 9/255, alpha: 1.0) } else { modernStatusPill.backgroundColor = UIColor(red: 230/255, green: 244/255, blue: 234/255, alpha: 1.0) modernStatusLabel.textColor = UIColor(red: 19/255, green: 115/255, blue: 51/255, alpha: 1.0) } // 3. Perangkat modernPerangkatLabel.text = certificateData.eqp_name.isEmpty ? "-" : certificateData.eqp_name // 4. Pemohon modernPemohonLabel.text = certificateData.cust_name.isEmpty ? "-" : certificateData.cust_name // 5. Merk & Model var mm = certificateData.merk if !certificateData.model.isEmpty && certificateData.model != "null" { mm = mm.isEmpty ? certificateData.model : "\(mm) • \(certificateData.model)" } modernMerkVal.text = mm.isEmpty ? "-" : mm // 6. Negara let negara = certificateData.negara.trimmingCharacters(in: .whitespacesAndNewlines) modernNegaraVal.text = (negara.isEmpty || negara == "null") ? "-" : negara // 7. Validity let tglBerlaku = CommonHelper.formatDate(from: certificateData.lic_date) let tglBerakhir = CommonHelper.formatDate(from: certificateData.exp_date) if tglBerlaku != "-" && tglBerakhir != "-" { modernValidityLabel.text = "Berlaku: \(tglBerlaku) s/d \(tglBerakhir)" } else if tglBerlaku != "-" { modernValidityLabel.text = "Berlaku: \(tglBerlaku)" } else { modernValidityLabel.text = "Masa Berlaku: -" } self.dataSertifikat = certificateData } @objc func onItemTap(sender: UITapGestureRecognizer) { cellDelegate?.openSertifikatDetail(data: dataSertifikat) } }