Skip to content
This repository has been archived by the owner on Oct 31, 2024. It is now read-only.

Commit

Permalink
feat(default-theme): show wish-list items qty in badge of header icon (
Browse files Browse the repository at this point in the history
  • Loading branch information
mkucmus authored Nov 25, 2020
1 parent 8d9492a commit 4d4cc78
Show file tree
Hide file tree
Showing 7 changed files with 169 additions and 15 deletions.
2 changes: 2 additions & 0 deletions api/composables.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,8 @@ export interface IUseWishlist {
// (undocumented)
clearWishlist: () => void;
// (undocumented)
count: Ref<number>;
// (undocumented)
isInWishlist: Ref<boolean>;
// (undocumented)
items: Ref<string[]>;
Expand Down
14 changes: 14 additions & 0 deletions docs/landing/resources/api/composables.iusewishlist.count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!-- Do not edit this file. It is automatically generated by API Documenter. -->

[Home](./index.md) &gt; [@shopware-pwa/composables](./composables.md) &gt; [IUseWishlist](./composables.iusewishlist.md) &gt; [count](./composables.iusewishlist.count.md)

## IUseWishlist.count property

> This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API in a production environment.
>
<b>Signature:</b>

```typescript
count: Ref<number>;
```
1 change: 1 addition & 0 deletions docs/landing/resources/api/composables.iusewishlist.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export interface IUseWishlist
| --- | --- | --- |
| [addToWishlist](./composables.iusewishlist.addtowishlist.md) | () =&gt; void | <b><i>(BETA)</i></b> |
| [clearWishlist](./composables.iusewishlist.clearwishlist.md) | () =&gt; void | <b><i>(BETA)</i></b> |
| [count](./composables.iusewishlist.count.md) | Ref&lt;number&gt; | <b><i>(BETA)</i></b> |
| [isInWishlist](./composables.iusewishlist.isinwishlist.md) | Ref&lt;boolean&gt; | <b><i>(BETA)</i></b> |
| [items](./composables.iusewishlist.items.md) | Ref&lt;string\[\]&gt; | <b><i>(BETA)</i></b> |
| [removeFromWishlist](./composables.iusewishlist.removefromwishlist.md) | (id: string) =&gt; void | <b><i>(BETA)</i></b> |
Expand Down
119 changes: 119 additions & 0 deletions packages/composables/__tests__/useWishlist.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import Vue from "vue";

// Mock Vue Composition API onMounted method
import VueCompositionApi, * as vueComp from "@vue/composition-api";
(vueComp.onMounted as any) = jest.fn();
Vue.use(VueCompositionApi);
import { useWishlist } from "@shopware-pwa/composables";

describe("Composables - useWishlist", () => {
const rootContextMock: any = {
$shopwareApiInstance: jest.fn(),
};
beforeEach(() => {
jest.clearAllMocks();
});

describe("computed", () => {
it("should return an empty array on frist useWishlist usage", () => {
const { items, count } = useWishlist(rootContextMock);
expect(items.value).toHaveLength(0);
expect(count.value).toBe(0);
});
it("should return false if the provided product does not exist or isn't in wishlist yet", () => {
const { isInWishlist } = useWishlist(rootContextMock);
expect(isInWishlist.value).toBe(false);
});
});
describe("methods", () => {
const product = {
id: "some-id",
};

describe("addToWishlist", () => {
it("should add to wishlist current product if id exists", () => {
const { addToWishlist, items, isInWishlist } = useWishlist(
rootContextMock,
product as any
);
addToWishlist();

expect(items.value[0]).toBe("some-id");
expect(isInWishlist.value).toBe(true);
});
it("should not add to wishlist current product if id does not exist or product is falsy", () => {
const { addToWishlist, isInWishlist } = useWishlist(
rootContextMock,
undefined as any
);
addToWishlist();

expect(isInWishlist.value).toBe(false);
});
});
describe("removeFromWishlist", () => {
it("should remove an item if it's included", () => {
const { addToWishlist, isInWishlist, removeFromWishlist } = useWishlist(
rootContextMock,
product as any
);
addToWishlist();

expect(isInWishlist.value).toBe(true);
removeFromWishlist(product.id);
expect(isInWishlist.value).toBe(false);
});
it("should remove an item without providing its id directly", () => {
const { addToWishlist, isInWishlist, removeFromWishlist } = useWishlist(
rootContextMock,
product as any
);
addToWishlist();

expect(isInWishlist.value).toBe(true);
removeFromWishlist(undefined as any);
expect(isInWishlist.value).toBe(false);
});
it("should not do anything when there is no product id", () => {
const { addToWishlist, isInWishlist, removeFromWishlist } = useWishlist(
rootContextMock,
{} as any
);
addToWishlist();

removeFromWishlist(undefined as any);
expect(isInWishlist.value).toBe(false);
});
it("should remove an item without providing its id directly", () => {
const { addToWishlist, isInWishlist, removeFromWishlist } = useWishlist(
rootContextMock,
product as any
);
addToWishlist();

expect(isInWishlist.value).toBe(true);
removeFromWishlist(undefined as any);
expect(isInWishlist.value).toBe(false);
});
});
describe("clearWishlist", () => {
it("should remove all items from wishlist", () => {
const { addToWishlist, items, clearWishlist } = useWishlist(
rootContextMock,
product as any
);
addToWishlist();

expect(items.value).toHaveLength(1);
clearWishlist();
expect(items.value).toHaveLength(0);
});
});
describe("onMounted", () => {
it("should invoke onMounted callback on composable init", () => {
useWishlist(rootContextMock);
expect(vueComp.onMounted).toBeCalled();
});
});
});
});
29 changes: 17 additions & 12 deletions packages/composables/src/logic/useWishlist.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import Vue from "vue";
import { ref, Ref, reactive, computed } from "@vue/composition-api";
import { ref, Ref, reactive, computed, onMounted } from "@vue/composition-api";
import { Product } from "@shopware-pwa/commons/interfaces/models/content/product/Product";
import { ApplicationVueContext, getApplicationContext } from "../appContext";

Expand All @@ -14,6 +14,7 @@ export interface IUseWishlist {
addToWishlist: () => void;
isInWishlist: Ref<boolean>;
items: Ref<string[]>;
count: Ref<number>;
}

const sharedWishlist = Vue.observable({
Expand All @@ -39,23 +40,25 @@ export const useWishlist = (
JSON.stringify(sharedWishlist.items)
);
};

/* istanbul ignore next */
const getFromStorage = () => {
if (typeof window != "undefined" && localStorage) {
return JSON.parse(localStorage.getItem("sw-wishlist-items") ?? "");
return JSON.parse(localStorage.getItem("sw-wishlist-items") ?? "[]");
}
};

if (!sharedWishlist.items.length) {
try {
const currentWishlist = getFromStorage();
if (currentWishlist) {
sharedWishlist.items = currentWishlist;
/* istanbul ignore next */
onMounted(() => {
if (!sharedWishlist.items.length) {
try {
const currentWishlist = getFromStorage();
if (Array.isArray(currentWishlist) && currentWishlist.length) {
sharedWishlist.items = currentWishlist;
}
} catch (error) {
console.error("useWishlist:getFromStorage", error);
}
} catch (error) {
console.log(error);
}
}
});

// removes item from the list
const removeFromWishlist = (itemId: string): void => {
Expand Down Expand Up @@ -94,12 +97,14 @@ export const useWishlist = (
};

const items = computed(() => localWishlist.items);
const count = computed(() => items.value.length);

return {
addToWishlist,
removeFromWishlist,
isInWishlist,
clearWishlist,
items,
count,
};
};
12 changes: 10 additions & 2 deletions packages/default-theme/src/components/SwHeaderIcons.vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
</SfDropdown>
<SfIcon
icon="heart"
:has-badge="wishlistCount > 0"
:badge-label="wishlistCount.toString()"
class="sf-header__icon sw-header__icon"
role="button"
:aria-label="$t('Go to wishlist')"
Expand All @@ -66,8 +68,12 @@

<script>
import { SfList, SfDropdown, SfIcon } from "@storefront-ui/vue"
import { useUser, useCart, useUIState } from "@shopware-pwa/composables"
import {
useUser,
useCart,
useUIState,
useWishlist,
} from "@shopware-pwa/composables"
import { PAGE_ACCOUNT, PAGE_WISHLIST } from "@/helpers/pages"
import SwPluginSlot from "sw-plugins/SwPluginSlot"
import SwButton from "@/components/atoms/SwButton"
Expand All @@ -83,6 +89,7 @@ export default {
setup(props, { root }) {
const { isLoggedIn, logout } = useUser(root)
const { count } = useCart(root)
const { count: wishlistCount } = useWishlist(root)
const { switchState: toggleSidebar } = useUIState(
root,
"CART_SIDEBAR_STATE"
Expand All @@ -98,6 +105,7 @@ export default {
toggleSidebar,
isLoggedIn,
logout,
wishlistCount,
}
},
data() {
Expand Down
7 changes: 6 additions & 1 deletion packages/default-theme/src/locales/en-GB.json
Original file line number Diff line number Diff line change
Expand Up @@ -177,5 +177,10 @@
"Enter promo code": "Enter promo code",
"Applied promo codes:": "Applied promo codes:",
"Promotion code added successfully": "Promotion code added successfully",
"Promotion code does not exist": "Promotion code does not exist"
"Promotion code does not exist": "Promotion code does not exist",
"Go to wishlist": "Go to wishlist",
"Tap any heart next to a product to favorite.": "Tap any heart next to a product to favorite.",
"We’ll save them for you here!": "We’ll save them for you here!",
"No favourites yet": "No favourites yet",
"Wishlist": "Wishlist"
}

1 comment on commit 4d4cc78

@vercel
Copy link

@vercel vercel bot commented on 4d4cc78 Nov 25, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.