// // SearchSertifikatNewVC.swift // Sirani // // Created by Hendi on 19/06/23. // Copyright © 2026 PT. Mitra Sinerji Teknoindo. All rights reserved. // import UIKit protocol SearchSertifikatNewDelegate { func onSearch(search: String, status: String, jenisLabel: String) } class SearchSertifikatNewVC: UIViewController { // Outlets / Views @IBOutlet weak var inputSearch: RoundTextField! @IBOutlet weak var optionsLayoutTV: UITableView! @IBOutlet weak var optionsLayout: UIView! @IBOutlet weak var optionsBg: UIView! @IBOutlet weak var btnStatusOptions: UIButton! // Initialize var delegate: SearchSertifikatNewDelegate? var backtoSertifikatPrivate = "unwindSearchToSertifikatSegueId" var backtoSertifikatPublic = "unwindSearchToSertifikatPublicSegueId" var isSertifikat = 1 var currentSearch: String = "" var currentStatus: String = "" // Constants value data private let statusSertifikatPrivateOptionItems = [ OptionItem(label: "Semua Sertifikat", value: ""), OptionItem(label: "Sertifikat Berlaku", value: "sertifkat_berlaku"), OptionItem(label: "Sertifikat Tidak Berlaku", value: "sertifikat_tidak_berlaku"), OptionItem(label: "Sertifikat Revisi", value: "sertifikat_revisi") ] private let statusSertifikatPublicOptionItems = [ OptionItem(label: "Sertifikat Terbit", value: "sertifikat_terbit"), OptionItem(label: "Sertifikat Dicabut", value: "sertifikat_dicabut") ] private let OPTION_JENIS_SERTIFIKAT_ID = 1 // Others private var selectedOptions = 0 private var selectedOptionItems = [OptionItem]() private var optionsShown = false // Result Values private var search = "" private var status = "" private var jenisLabel = "Semua" // Modern UI Elements private let chipContainerStack = UIStackView() private var chipButtons = [UIButton]() private let modernCard = UIView() private let modernSearchIcon = UIImageView() private let btnApplyModern = UIButton(type: .system) private let btnResetModern = UIButton(type: .system) private var isModernFilterBuilt = false // View Lifecycles override var preferredStatusBarStyle: UIStatusBarStyle { return .lightContent } override func viewWillAppear(_ animated: Bool) { super.viewWillAppear(animated) setupInitialState() updateToolbarTitle() buildModernFilterUI() updateChipSelection() } override func viewDidLoad() { super.viewDidLoad() optionsLayoutTV.delegate = self optionsLayoutTV.dataSource = self optionsLayoutTV.tableFooterView = UIView() let tapDismiss = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard)) tapDismiss.cancelsTouchesInView = false view.addGestureRecognizer(tapDismiss) } @objc private func dismissKeyboard() { view.endEditing(true) } private func setupInitialState() { if !currentSearch.isEmpty { search = currentSearch inputSearch.text = currentSearch } else { search = inputSearch.text ?? "" } if isSertifikat == 2 { // Public certificates if currentStatus == "sertifikat_dicabut" { status = "sertifikat_dicabut" jenisLabel = "Sertifikat Dicabut" } else { status = "sertifikat_terbit" jenisLabel = "Sertifikat Terbit" } } else { // Private certificates if !currentStatus.isEmpty { status = currentStatus if let matched = statusSertifikatPrivateOptionItems.first(where: { ($0.value as? String) == currentStatus }) { jenisLabel = matched.label } else { jenisLabel = "Sertifikat Berlaku" } } else { status = "" jenisLabel = "Semua Sertifikat" } } btnStatusOptions.setTitle(jenisLabel, for: .normal) hideOptions() } private func updateToolbarTitle() { // Find Toolbar Title in subviews and set modern title for subview in view.subviews { for inner in subview.subviews { if let lbl = inner as? UILabel, lbl.text?.lowercased().contains("search") == true { lbl.text = "Filter & Pencarian" lbl.font = UIFont.systemFont(ofSize: 18, weight: .bold) } } } } private func buildModernFilterUI() { guard !isModernFilterBuilt else { return } isModernFilterBuilt = true // Style search input inputSearch.layer.cornerRadius = 12 inputSearch.layer.borderWidth = 1 inputSearch.layer.borderColor = UIColor(red: 226/255, green: 232/255, blue: 240/255, alpha: 1.0).cgColor inputSearch.backgroundColor = UIColor(red: 250/255, green: 251/255, blue: 253/255, alpha: 1.0) inputSearch.placeholder = "Cari nomor sertifikat, pemohon, model..." inputSearch.clearButtonMode = .whileEditing // Hide legacy dropdown button & arrow and build modern interactive chips btnStatusOptions.isHidden = true if let arrowImg = btnStatusOptions.superview?.subviews.first(where: { ($0 as? UIImageView)?.image == UIImage(named: "dropdown") }) { arrowImg.isHidden = true } // Find existing CARI and RESET buttons and hide them so we can use our modern action buttons for subview in view.subviews { findAndHideLegacyActionButtons(in: subview) } guard let container = btnStatusOptions.superview else { return } // Build Chip Stack chipContainerStack.translatesAutoresizingMaskIntoConstraints = false chipContainerStack.axis = .horizontal chipContainerStack.distribution = .fillEqually chipContainerStack.spacing = 8 chipContainerStack.alignment = .fill container.addSubview(chipContainerStack) let activeOptions = (isSertifikat == 2) ? statusSertifikatPublicOptionItems : statusSertifikatPrivateOptionItems chipButtons.removeAll() for item in activeOptions { let btn = UIButton(type: .system) btn.translatesAutoresizingMaskIntoConstraints = false btn.setTitle(item.label, for: .normal) btn.titleLabel?.font = UIFont.systemFont(ofSize: 12, weight: .semibold) btn.layer.cornerRadius = 10 btn.layer.borderWidth = 1 btn.tag = activeOptions.firstIndex(where: { $0.label == item.label }) ?? 0 btn.addTarget(self, action: #selector(onChipTapped(_:)), for: .touchUpInside) chipButtons.append(btn) chipContainerStack.addArrangedSubview(btn) } NSLayoutConstraint.activate([ chipContainerStack.topAnchor.constraint(equalTo: btnStatusOptions.topAnchor), chipContainerStack.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 16), chipContainerStack.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -16), chipContainerStack.heightAnchor.constraint(equalToConstant: 44) ]) // Modern Action Buttons: Terapkan Filter & Reset let buttonStack = UIStackView() buttonStack.translatesAutoresizingMaskIntoConstraints = false buttonStack.axis = .vertical buttonStack.spacing = 10 container.addSubview(buttonStack) // 1. Primary Button btnApplyModern.translatesAutoresizingMaskIntoConstraints = false btnApplyModern.setTitle("🔍 TERAPKAN FILTER", for: .normal) btnApplyModern.titleLabel?.font = UIFont.systemFont(ofSize: 14, weight: .bold) btnApplyModern.setTitleColor(.white, for: .normal) btnApplyModern.backgroundColor = UIColor.siraniPrimaryBlue btnApplyModern.layer.cornerRadius = 12 btnApplyModern.layer.masksToBounds = false btnApplyModern.layer.shadowColor = UIColor.siraniPrimaryBlue.cgColor btnApplyModern.layer.shadowOffset = CGSize(width: 0, height: 4) btnApplyModern.layer.shadowRadius = 8 btnApplyModern.layer.shadowOpacity = 0.25 btnApplyModern.addTarget(self, action: #selector(onSearchTapped(_:)), for: .touchUpInside) NSLayoutConstraint.activate([ btnApplyModern.heightAnchor.constraint(equalToConstant: 48) ]) buttonStack.addArrangedSubview(btnApplyModern) // 2. Secondary Reset Button btnResetModern.translatesAutoresizingMaskIntoConstraints = false btnResetModern.setTitle("↺ Reset Filter", for: .normal) btnResetModern.titleLabel?.font = UIFont.systemFont(ofSize: 13, weight: .semibold) btnResetModern.setTitleColor(UIColor(red: 100/255, green: 116/255, blue: 139/255, alpha: 1.0), for: .normal) btnResetModern.backgroundColor = UIColor(red: 241/255, green: 245/255, blue: 249/255, alpha: 1.0) btnResetModern.layer.cornerRadius = 12 btnResetModern.layer.borderWidth = 1 btnResetModern.layer.borderColor = UIColor(red: 226/255, green: 232/255, blue: 240/255, alpha: 1.0).cgColor btnResetModern.addTarget(self, action: #selector(onResetTapped(_:)), for: .touchUpInside) NSLayoutConstraint.activate([ btnResetModern.heightAnchor.constraint(equalToConstant: 44) ]) buttonStack.addArrangedSubview(btnResetModern) NSLayoutConstraint.activate([ buttonStack.topAnchor.constraint(equalTo: chipContainerStack.bottomAnchor, constant: 28), buttonStack.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: 16), buttonStack.trailingAnchor.constraint(equalTo: container.trailingAnchor, constant: -16) ]) } private func findAndHideLegacyActionButtons(in view: UIView) { for sub in view.subviews { if let btn = sub as? UIButton { let title = btn.title(for: .normal)?.uppercased() ?? "" if (title == "CARI" || title == "RESET") && btn != btnApplyModern && btn != btnResetModern { btn.isHidden = true } } findAndHideLegacyActionButtons(in: sub) } } @objc private func onChipTapped(_ sender: UIButton) { let activeOptions = (isSertifikat == 2) ? statusSertifikatPublicOptionItems : statusSertifikatPrivateOptionItems guard sender.tag < activeOptions.count else { return } let item = activeOptions[sender.tag] status = item.value as! String jenisLabel = item.label btnStatusOptions.setTitle(jenisLabel, for: .normal) updateChipSelection() } private func updateChipSelection() { let activeOptions = (isSertifikat == 2) ? statusSertifikatPublicOptionItems : statusSertifikatPrivateOptionItems for btn in chipButtons { guard btn.tag < activeOptions.count else { continue } let item = activeOptions[btn.tag] let isSelected = (item.value as! String) == status if isSelected { btn.backgroundColor = UIColor.siraniPrimaryBlue btn.setTitleColor(.white, for: .normal) btn.layer.borderColor = UIColor.siraniPrimaryBlue.cgColor } else { btn.backgroundColor = UIColor(red: 248/255, green: 250/255, blue: 253/255, alpha: 1.0) btn.setTitleColor(UIColor(red: 71/255, green: 85/255, blue: 105/255, alpha: 1.0), for: .normal) btn.layer.borderColor = UIColor(red: 226/255, green: 232/255, blue: 240/255, alpha: 1.0).cgColor } } } @IBAction func onInputSearchKeyTap(_ sender: Any) { view.endEditing(true) onSearchTapped(sender) } @IBAction func unwindToSertifikatNew(_ sender: Any) { if optionsShown { hideOptions() } else { if isSertifikat == 2 { performSegue(withIdentifier: backtoSertifikatPublic, sender: self) } else { performSegue(withIdentifier: backtoSertifikatPrivate, sender: self) } } } @IBAction func onJenisSertifikatOptionsTapped(_ sender: Any) { selectedOptions = OPTION_JENIS_SERTIFIKAT_ID selectedOptionItems.removeAll() if isSertifikat == 2 { selectedOptionItems += statusSertifikatPublicOptionItems } else { selectedOptionItems += statusSertifikatPrivateOptionItems } optionsLayoutTV.reloadData() showOptions() } @IBAction func onResetTapped(_ sender: Any) { search = "" inputSearch.text = "" if isSertifikat == 2 { status = "sertifikat_terbit" jenisLabel = "Sertifikat Terbit" } else { status = "" jenisLabel = "Semua Sertifikat" } btnStatusOptions.setTitle(jenisLabel, for: .normal) updateChipSelection() } @IBAction func onSearchTapped(_ sender: Any) { view.endEditing(true) let searchText = inputSearch.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" search = searchText self.delegate?.onSearch(search: search, status: status, jenisLabel: jenisLabel) if isSertifikat == 2 { performSegue(withIdentifier: backtoSertifikatPublic, sender: self) } else { performSegue(withIdentifier: backtoSertifikatPrivate, sender: self) } } private func showOptions() { optionsLayout.show() optionsShown = true } @objc private func hideOptions() { optionsLayout.hide() optionsShown = false } } extension SearchSertifikatNewVC: UITableViewDelegate, UITableViewDataSource { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return selectedOptionItems.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { if let cell = tableView.dequeueReusableCell(withIdentifier: "searchSertifikatNewCell", for: indexPath) as? OptionsCell { let optionItem = selectedOptionItems[indexPath.row] cell.updateViews(item: optionItem) return cell } else { return OptionsCell() } } func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { if selectedOptions == OPTION_JENIS_SERTIFIKAT_ID { status = selectedOptionItems[indexPath.row].value as! String jenisLabel = selectedOptionItems[indexPath.row].label btnStatusOptions.setTitle(jenisLabel, for: .normal) updateChipSelection() } hideOptions() } }