Manos Chorianopoulos

CategoryOffers part2

......@@ -9,10 +9,118 @@ import UIKit
@objc(CategoryOfferCollectionViewCell)
public class CategoryOfferCollectionViewCell: UICollectionViewCell {
@IBOutlet weak var parentView: UIView!
@IBOutlet weak var bannerImage: UIImageView!
@IBOutlet weak var logoImage: UIImageView!
@IBOutlet weak var discountView: UIView!
@IBOutlet weak var discountLabel: UILabel!
@IBOutlet weak var merchantNameLabel: UILabel!
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var subtitleLabel: UILabel!
@IBOutlet weak var expirationLabel: UILabel!
var postImageURL: String? {
didSet {
if let url = postImageURL {
self.bannerImage.image = UIImage()
UIImage.loadImageUsingCacheWithUrlString(url) { image in
if url == self.postImageURL {
self.bannerImage.image = image
}
}
} else {
self.bannerImage.image = nil
}
}
}
var logoImageURL: String? {
didSet {
if let url = logoImageURL {
self.logoImage.image = UIImage()
UIImage.loadImageUsingCacheWithUrlString(url) { image in
if url == self.logoImageURL {
self.logoImage.image = image
}
}
} else {
self.logoImage.image = nil
}
}
}
public override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
parentView.layer.borderWidth = 1.0
parentView.layer.borderColor = UIColor(rgb: 0xD2D6D9).cgColor
parentView.layer.cornerRadius = 12.0
parentView.clipsToBounds = true
logoImage.layer.cornerRadius = 8.0
logoImage.clipsToBounds = true
logoImage.backgroundColor = UIColor(rgb: 0xEEEEEE)
discountView.layer.cornerRadius = 17.0
discountView.clipsToBounds = true
}
func configureCell(data: OfferModel) {
bannerImage.image = UIImage(named: data.bannerImage, in: Bundle.frameworkResourceBundle, compatibleWith: nil)
discountLabel.text = data.discount
discountLabel.font = UIFont(name: "PingLCG-Bold", size: 14)
discountLabel.textColor = UIColor(rgb: 0xFFFFFF)
discountView.backgroundColor = UIColor(rgb: 0xCBCBCB)
merchantNameLabel.text = data.title
merchantNameLabel.font = UIFont(name: "PingLCG-Regular", size: 12)
merchantNameLabel.textColor = UIColor(rgb: 0x000F1E)
titleLabel.text = data.title
titleLabel.font = UIFont(name: "PingLCG-Bold", size: 15)
titleLabel.textColor = UIColor(rgb: 0x000F1E)
subtitleLabel.text = data.description
subtitleLabel.font = UIFont(name: "PingLCG-Regular", size: 13)
subtitleLabel.textColor = UIColor(rgb: 0x00111B)
expirationLabel.text = data.expirationDate
expirationLabel.font = UIFont(name: "PingLCG-Regular", size: 12)
expirationLabel.textColor = UIColor(rgb: 0x9BA1A6)
logoImage.image = UIImage(named: data.merchantLogo, in: Bundle.frameworkResourceBundle, compatibleWith: nil)
}
func configureCell(data: CouponSetItemModel) {
self.postImageURL = data._app_img_preview
discountLabel.text = data._discount
discountLabel.font = UIFont(name: "PingLCG-Bold", size: 14)
discountLabel.textColor = UIColor(rgb: 0xFFFFFF)
discountView.backgroundColor = UIColor(rgb: 0xCBCBCB)
if let merchant = data._merchant {
merchantNameLabel.text = merchant._admin_name
self.logoImageURL = merchant._img_preview
} else {
merchantNameLabel.text = ""
self.logoImageURL = nil
}
merchantNameLabel.font = UIFont(name: "PingLCG-Regular", size: 12)
merchantNameLabel.textColor = UIColor(rgb: 0x000F1E)
titleLabel.text = data._name
titleLabel.font = UIFont(name: "PingLCG-Bold", size: 15)
titleLabel.textColor = UIColor(rgb: 0x000F1E)
subtitleLabel.text = data._short_description
subtitleLabel.font = UIFont(name: "PingLCG-Regular", size: 13)
subtitleLabel.textColor = UIColor(rgb: 0x00111B)
expirationLabel.text = "until " + data.formattedEndDate(format: "dd-MM")
expirationLabel.font = UIFont(name: "PingLCG-Regular", size: 12)
expirationLabel.textColor = UIColor(rgb: 0x9BA1A6)
}
}
......
......@@ -18,21 +18,11 @@ public class CategoryOffersGridTableViewCell: UITableViewCell {
public override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
setupCollectionView()
}
public override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
private func setupCollectionView() {
collectionView.delegate = self
collectionView.dataSource = self
collectionView.backgroundColor = .clear
collectionView.isScrollEnabled = false // Scroll is handled by the outer TableView
collectionView.isScrollEnabled = false
XIBLoader.registerCollectionViewCell(
collectionView,
......@@ -42,22 +32,44 @@ public class CategoryOffersGridTableViewCell: UITableViewCell {
)
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
layout.minimumInteritemSpacing = 16
layout.minimumInteritemSpacing = 12
layout.minimumLineSpacing = 16
layout.sectionInset = UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
}
}
public override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
}
func configureCell(with sectionData: SectionModel?, parentViewController: UIViewController?) {
self.data = sectionData
self.parentViewController = parentViewController
collectionView.reloadData()
// Use layoutIfNeeded to calculate content size and set the height constraint
collectionView.layoutIfNeeded()
let height = collectionView.collectionViewLayout.collectionViewContentSize.height
collectionViewHeightConstraint.constant = height
// Calculate and set the collection view height so the table view cell expands correctly
DispatchQueue.main.async {
self.collectionView.layoutIfNeeded()
let height = self.collectionView.collectionViewLayout.collectionViewContentSize.height
self.collectionViewHeightConstraint.constant = max(height, 1)
// Notify the parent table view to recalculate its layout
if let tableView = self.parentViewController?.view.subviews.first(where: { $0 is UITableView }) as? UITableView {
tableView.beginUpdates()
tableView.endUpdates()
}
}
}
// Compute item size for 2-column grid
private func itemSize() -> CGSize {
let totalWidth = collectionView.bounds.width > 0 ? collectionView.bounds.width : UIScreen.main.bounds.width
let inset: CGFloat = 16
let spacing: CGFloat = 12
let availableWidth = totalWidth - (inset * 2) - spacing
let itemWidth = floor(availableWidth / 2)
let itemHeight = itemWidth * 1.65 // ratio matching the design card proportions
return CGSize(width: itemWidth, height: itemHeight)
}
}
......@@ -101,38 +113,35 @@ extension CategoryOffersGridTableViewCell: UICollectionViewDataSource, UICollect
return
}
// Handle navigation based on item type
switch data.itemType {
case .couponSets:
if let couponSet = items[indexPath.row] as? CouponSetItemModel {
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.frameworkResourceBundle)
if let vc = storyboard.instantiateViewController(withIdentifier: "CouponsetViewController") as? CouponsetViewController {
let vc = CouponsetViewController(nibName: "CouponsetViewController", bundle: Bundle.frameworkResourceBundle)
vc.couponset = couponSet
self.parentViewController?.navigationController?.pushViewController(vc, animated: true)
}
parentViewController?.navigationController?.pushViewController(vc, animated: true)
}
default:
if let offer = items[indexPath.row] as? OfferModel {
// Determine if it's a campaign or other offer and navigate appropriately
// (Using existing patterns from MyRewardsViewController)
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.frameworkResourceBundle)
if let vc = storyboard.instantiateViewController(withIdentifier: "CampaignViewController") as? CampaignViewController {
vc.campaignUrl = offer.campaignUrl // Assuming OfferModel has this
self.parentViewController?.navigationController?.pushViewController(vc, animated: true)
}
let vc = CouponViewController(nibName: "CouponViewController", bundle: Bundle.frameworkResourceBundle)
vc.offer = offer
parentViewController?.navigationController?.pushViewController(vc, animated: true)
}
}
}
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// Calculate width for 2 columns with spacing
let padding: CGFloat = 16 * 3 // left + middle + right padding
let availableWidth = collectionView.frame.width - padding
let itemWidth = availableWidth / 2
return itemSize()
}
// Adjust height as needed based on design (aspect ratio or fixed)
let itemHeight = itemWidth * 1.3 // Approximation from screenshot
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
return 16
}
return CGSize(width: itemWidth, height: itemHeight)
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
return 12
}
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAt section: Int) -> UIEdgeInsets {
return UIEdgeInsets(top: 16, left: 16, bottom: 16, right: 16)
}
}
......
......@@ -10,6 +10,7 @@ import UIKit
protocol MyRewardsOffersScrollTableViewCellDelegate: AnyObject {
func didSelectOffer(_ offer: OfferModel)
func didSelectCouponSet(_ couponSet: CouponSetItemModel)
func didSelectAllOffers(_ section: SectionModel)
}
@objc(MyRewardsOffersScrollTableViewCell)
......@@ -29,19 +30,19 @@ public class MyRewardsOffersScrollTableViewCell: UITableViewCell {
super.awakeFromNib()
// Initialization code
// allButtonView.layer.borderWidth = 1.0
// allButtonView.layer.borderColor = UIColor(rgb: 0x000F1E).cgColor
// allButtonView.layer.cornerRadius = 4.0
allButtonArrowImage.image = UIImage(named: "arrow_right_blue", in: Bundle.frameworkResourceBundle, compatibleWith: nil)
// allButtonLabel.text = "Όλα"
allButtonLabel.text = "All"
allButtonLabel.font = UIFont(name: "PingLCG-Regular", size: 15)
allButtonLabel.textColor = UIColor(rgb: 0x004E6E)
allButtonLabel.frame.size.width = allButtonLabel.intrinsicContentSize.width
allButtonLabel.frame.size.height = allButtonLabel.intrinsicContentSize.height
// Add tap gesture to allButtonView
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(allButtonTapped))
allButtonView.isUserInteractionEnabled = true
allButtonView.addGestureRecognizer(tapGesture)
// UPDATED: Safe XIB registration for collection view cells
registerCollectionViewCells()
......@@ -56,6 +57,11 @@ public class MyRewardsOffersScrollTableViewCell: UITableViewCell {
collectionView.dataSource = self
}
@objc private func allButtonTapped() {
guard let data = data else { return }
delegate?.didSelectAllOffers(data)
}
// NEW: Safe collection view cell registration
private func registerCollectionViewCells() {
XIBLoader.registerCollectionViewCell(
......@@ -109,20 +115,11 @@ public class MyRewardsOffersScrollTableViewCell: UITableViewCell {
collectionViewBottom.constant = 0
}
// Update collection view height based on section
// if data?.title == "Αγαπημένα" {
// collectionViewHeightConstraint.constant = 350 // Match cell height
// } else {
collectionViewHeightConstraint.constant = 232 // Default height
// }
// Configure layout based on section type
if let layout = collectionView.collectionViewLayout as? UICollectionViewFlowLayout {
// if data?.title == "Αγαπημένα" {
// layout.minimumLineSpacing = 24
// } else {
layout.minimumLineSpacing = 7
// }
}
let catBoldText = (data?.title ?? "") + " "
......@@ -138,13 +135,11 @@ public class MyRewardsOffersScrollTableViewCell: UITableViewCell {
categoryLabel.attributedText = catAttributedString
self.collectionView.reloadData();
}
}
extension MyRewardsOffersScrollTableViewCell: UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {
public func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
......@@ -189,11 +184,9 @@ extension MyRewardsOffersScrollTableViewCell: UICollectionViewDataSource, UIColl
switch data.itemType {
case .couponSets:
if let couponSet = items[indexPath.row] as? CouponSetItemModel {
// Pass CouponSetItemModel directly to new delegate method
delegate?.didSelectCouponSet(couponSet)
}
default:
// Handle OfferModel directly for ProfileViewController compatibility
if let offer = items[indexPath.row] as? OfferModel {
delegate?.didSelectOffer(offer)
}
......@@ -202,20 +195,12 @@ extension MyRewardsOffersScrollTableViewCell: UICollectionViewDataSource, UIColl
// MARK: - UICollectionViewDelegateFlowLayout
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
// if self.data?.title == "Αγαπημένα" {
// return CGSize(width: 275, height: 350)
// } else {
return CGSize(width: 257, height: 232)
// }
}
// Distance Between Item Cells
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
// if self.data?.title == "Αγαπημένα" {
// return 24
// } else {
return 7
// }
}
public func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAt section: Int) -> CGFloat {
......
......@@ -25,43 +25,54 @@ import UIKit
private func setupTableView() {
tableView.delegate = self
tableView.dataSource = self
tableView.separatorStyle = .none
tableView.backgroundColor = .white
tableView.estimatedRowHeight = 100
tableView.rowHeight = UITableView.automaticDimension
tableView.register(UINib(nibName: "CategoryOffersHeaderTableViewCell", bundle: Bundle.frameworkResourceBundle), forCellReuseIdentifier: "CategoryOffersHeaderTableViewCell")
tableView.register(UINib(nibName: "CategoryOffersGridTableViewCell", bundle: Bundle.frameworkResourceBundle), forCellReuseIdentifier: "CategoryOffersGridTableViewCell")
tableView.register(
UINib(nibName: "CategoryOffersHeaderTableViewCell", bundle: Bundle.frameworkResourceBundle),
forCellReuseIdentifier: "CategoryOffersHeaderTableViewCell"
)
tableView.register(
UINib(nibName: "CategoryOffersGridTableViewCell", bundle: Bundle.frameworkResourceBundle),
forCellReuseIdentifier: "CategoryOffersGridTableViewCell"
)
}
}
extension CategoryOffersViewController: UITableViewDelegate, UITableViewDataSource {
public func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 2 // Header + Grid
return 2 // Row 0: Header, Row 1: Grid
}
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if indexPath.row == 0 {
let cell = tableView.dequeueReusableCell(withIdentifier: "CategoryOffersHeaderTableViewCell", for: indexPath) as! CategoryOffersHeaderTableViewCell
if let title = sectionData?.title {
cell.headerLabel.text = title
}
cell.headerLabel.text = sectionData?.title ?? ""
cell.selectionStyle = .none
return cell
} else {
let cell = tableView.dequeueReusableCell(withIdentifier: "CategoryOffersGridTableViewCell", for: indexPath) as! CategoryOffersGridTableViewCell
cell.configureCell(with: sectionData, parentViewController: self)
cell.selectionStyle = .none
return cell
}
}
public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 {
return UITableView.automaticDimension
} else {
return UITableView.automaticDimension // Or a calculated height depending on content
}
public func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row == 0 {
return 100
}
return 600
}
}
......
......@@ -802,4 +802,15 @@ extension MyRewardsViewController: MyRewardsOffersScrollTableViewCellDelegate {
func didSelectCouponSet(_ couponSet: CouponSetItemModel) {
openCouponsetViewController(with: couponSet)
}
func didSelectAllOffers(_ section: SectionModel) {
let vc = CategoryOffersViewController(nibName: "CategoryOffersViewController", bundle: Bundle.frameworkResourceBundle)
vc.sectionData = section
if let navigationController = self.navigationController {
navigationController.pushViewController(vc, animated: true)
} else {
vc.modalPresentationStyle = .fullScreen
self.present(vc, animated: true, completion: nil)
}
}
}
......
......@@ -545,6 +545,11 @@ extension ProfileViewController: MyRewardsOffersScrollTableViewCellDelegate {
// ProfileViewController doesn't handle coupon sets, so just log
print("CouponSet selected in ProfileViewController: \(couponSet._name)")
}
func didSelectAllOffers(_ section: SectionModel) {
// ProfileViewController doesn't navigate to category offers
print("⚠️ [ProfileVC] didSelectAllOffers — not handled")
}
}
// Add delegate conformance
......