make favorite state persistant with api

This commit is contained in:
kusowl 2026-03-05 13:34:37 +05:30
parent b575b42f22
commit 7e1ecf35b9
10 changed files with 50 additions and 39 deletions

1
.rgignore Normal file
View File

@ -0,0 +1 @@
backend/

View File

@ -11,6 +11,7 @@ export interface ProductModel {
category: Category;
productImages: string[];
updatedAt: string;
isFavorite: boolean;
}
export interface ProductCollection extends PaginatedResponse<ProductModel> {}

View File

@ -1,8 +1,8 @@
import { TestBed } from '@angular/core/testing';
import { TestBed } from "@angular/core/testing";
import { FavoriteService } from './favorite-service';
import { FavoriteService } from "./favorite-service";
describe('FavoriteService', () => {
describe("FavoriteService", () => {
let service: FavoriteService;
beforeEach(() => {
@ -10,7 +10,7 @@ describe('FavoriteService', () => {
service = TestBed.inject(FavoriteService);
});
it('should be created', () => {
it("should be created", () => {
expect(service).toBeTruthy();
});
});

View File

@ -1,6 +1,6 @@
import { HttpClient } from '@angular/common/http';
import { inject, Injectable } from '@angular/core';
import { API_URL } from '../tokens/api-url-tokens';
import { HttpClient } from "@angular/common/http";
import { inject, Injectable } from "@angular/core";
import { API_URL } from "../tokens/api-url-tokens";
export interface FavoriteResponse {
message: string;
@ -8,7 +8,7 @@ export interface FavoriteResponse {
}
@Injectable({
providedIn: 'root',
providedIn: "root",
})
export class FavoriteService {
http = inject(HttpClient);

View File

@ -1,15 +1,19 @@
<div class="card flex flex-col relative cursor-pointer" (click)="goToProductDetails()">
<app-favorite-button [productId]="product.id" class="absolute top-5 right-5" />
<app-favorite-button
[productId]="product.id"
[isFavorite]="product.isFavorite"
class="absolute top-5 right-5"
/>
<!--Product image-->
<div class="bg-gray-200 rounded-xl h-40">
<img [src]="product.productImages[0]" alt="" class="object-cover rounded-xl w-full h-full" />
</div>
<p class="text-gray-400 text-sm truncate">{{product.title}}</p>
<p class="text-gray-400 text-sm truncate">{{ product.title }}</p>
<p class="text-gray-400 text-xs">⭐4.5</p>
<p class="text-gray-400 text-xs">
Price:
<span class="line-through italic mr-1">{{product.actualPrice}}</span>
<span class="font-bold">{{product.listPrice}}/-</span>
<span class="line-through italic mr-1">{{ product.actualPrice }}</span>
<span class="font-bold">{{ product.listPrice }}/-</span>
</p>
</div>

View File

@ -1,13 +1,13 @@
import { Component, inject, Input } from '@angular/core';
import { ProductModel } from '../../../../core/models/product.model';
import { Router } from '@angular/router';
import { FavoriteButton } from '../../../../src/app/shared/components/favorite-button/favorite-button';
import { Component, inject, Input } from "@angular/core";
import { ProductModel } from "../../../../core/models/product.model";
import { Router } from "@angular/router";
import { FavoriteButton } from "../../../../src/app/shared/components/favorite-button/favorite-button";
@Component({
selector: 'app-product-card',
selector: "app-product-card",
standalone: true,
imports: [FavoriteButton],
templateUrl: './product-card.html',
templateUrl: "./product-card.html",
})
export class ProductCard {
readonly router = inject(Router);

View File

@ -1,10 +1,10 @@
import { inject, Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { API_URL } from '../../../core/tokens/api-url-tokens';
import { ProductCollection, ProductModel } from '../../../core/models/product.model';
import { inject, Injectable } from "@angular/core";
import { HttpClient } from "@angular/common/http";
import { API_URL } from "../../../core/tokens/api-url-tokens";
import { ProductCollection, ProductModel } from "../../../core/models/product.model";
@Injectable({
providedIn: 'root',
providedIn: "root",
})
export class ProductService {
http = inject(HttpClient);

View File

@ -1,7 +1,13 @@
<!--Favorite button -->
<button
(click)="$event.stopPropagation(); toggleFavorite($event)"
class="transition-all duration-300 ease active:scale-80 hover:bg-gray-100 p-1 rounded-full"
class="transition-all duration-300 ease active:scale-80 hover:bg-gray-100 p-1 rounded-full flex items-center justify-center"
>
<lucide-angular [img]="HeartIcon" class="w-4 h-4 text-gray-500" />
<lucide-angular
[img]="HeartIcon"
[class.text-gray-500]="!isFavorite"
[class.text-red-400]="isFavorite"
[class]="isFavorite ? 'fill-red-500' : 'fill-none'"
class="w-4 h-4 transition-colors duration-200"
/>
</button>

View File

@ -1,23 +1,22 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ComponentFixture, TestBed } from "@angular/core/testing";
import { FavoriteButton } from './favorite-button';
import { FavoriteButton } from "./favorite-button";
describe('FavoriteButton', () => {
describe("FavoriteButton", () => {
let component: FavoriteButton;
let fixture: ComponentFixture<FavoriteButton>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [FavoriteButton]
})
.compileComponents();
imports: [FavoriteButton],
}).compileComponents();
fixture = TestBed.createComponent(FavoriteButton);
component = fixture.componentInstance;
await fixture.whenStable();
});
it('should create', () => {
it("should create", () => {
expect(component).toBeTruthy();
});
});

View File

@ -1,16 +1,16 @@
import { Component, inject, Input } from '@angular/core';
import { HeartIcon, LucideAngularModule } from 'lucide-angular';
import { FavoriteService } from '../../../../../core/services/favorite-service';
import { Component, inject, Input } from "@angular/core";
import { HeartIcon, LucideAngularModule } from "lucide-angular";
import { FavoriteService } from "../../../../../core/services/favorite-service";
@Component({
selector: 'app-favorite-button',
selector: "app-favorite-button",
imports: [LucideAngularModule],
templateUrl: './favorite-button.html',
styleUrl: './favorite-button.css',
templateUrl: "./favorite-button.html",
styleUrl: "./favorite-button.css",
})
export class FavoriteButton {
@Input({ required: true }) productId!: number;
@Input() isFavorite = true;
@Input() isFavorite = false;
favoriteService = inject(FavoriteService);