diff --git a/src/api/BarAssistantClient.ts b/src/api/BarAssistantClient.ts
index 7c627791..40def81c 100644
--- a/src/api/BarAssistantClient.ts
+++ b/src/api/BarAssistantClient.ts
@@ -29,7 +29,7 @@ const authMiddleware: Middleware = {
const scopedState = new AppState()
accessToken = scopedState.token
request.headers.set("Authorization", `Bearer ${accessToken}`);
- request.headers.set("Accept", "application/json");
+ // request.headers.set("Accept", "application/json");
return request;
},
};
@@ -172,6 +172,10 @@ export default class BarAssistantClient {
return (await client.GET('/users/{id}/cocktails/favorites', { params: { path: { id: id }, query: { per_page: 500 } } })).data
}
+ static async getUserCocktailShelf(id: number) {
+ return (await client.GET('/users/{id}/cocktails', { params: { path: { id: id }, query: { per_page: 500 } } })).data
+ }
+
static async getNotes(query = {}) {
return (await client.GET('/notes', { params: { query: query } })).data
}
@@ -526,4 +530,16 @@ export default class BarAssistantClient {
static async removeFromBarShelf(id: number, data: {}) {
return (await client.POST('/bars/{id}/ingredients/batch-delete', { params: { path: { id: id } }, body: data })).data
}
+
+ static async getCocktailPrices(id: string) {
+ return (await client.GET('/cocktails/{id}/prices', { params: { path: { id: id } } })).data
+ }
+
+ static async getBarShelfCocktails(id: number) {
+ return (await client.GET('/bars/{id}/cocktails', { params: { path: { id: id }, query: { per_page: 500 } } })).data
+ }
+
+ static async getMenuExport() {
+ return (await client.GET('/menu/export', {parseAs: 'text'})).data
+ }
}
\ No newline at end of file
diff --git a/src/api/api.d.ts b/src/api/api.d.ts
index 38b9641f..06ddb7f2 100644
--- a/src/api/api.d.ts
+++ b/src/api/api.d.ts
@@ -355,6 +355,26 @@ export interface paths {
patch?: never;
trace?: never;
};
+ "/cocktails/{id}/prices": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /**
+ * Show cocktail prices
+ * @description Shows a list of cocktail prices grouped per available price categories. Missing ingredient prices are skipped.
+ */
+ get: operations["getCocktailPrices"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
"/cocktail-methods": {
parameters: {
query?: never;
@@ -839,6 +859,26 @@ export interface paths {
patch?: never;
trace?: never;
};
+ "/menu/export": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /**
+ * Export menu
+ * @description Export menu as CSV
+ */
+ get: operations["69581b120488a658b86369819bd257e0"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
"/notes": {
parameters: {
query?: never;
@@ -1162,6 +1202,26 @@ export interface paths {
patch?: never;
trace?: never;
};
+ "/bars/{id}/cocktails": {
+ parameters: {
+ query?: never;
+ header?: never;
+ path?: never;
+ cookie?: never;
+ };
+ /**
+ * Show a list bar shelf cocktails
+ * @description Cocktails that the bar can make with ingredients on their shelf
+ */
+ get: operations["40813734b16874942a79324150fb3dd1"];
+ put?: never;
+ post?: never;
+ delete?: never;
+ options?: never;
+ head?: never;
+ patch?: never;
+ trace?: never;
+ };
"/users/{id}/shopping-list": {
parameters: {
query?: never;
@@ -1495,6 +1555,8 @@ export interface components {
/** @example 1 */
total_shelf_ingredients: number;
/** @example 1 */
+ total_bar_shelf_cocktails?: number;
+ /** @example 1 */
total_bar_members: number;
/** @example 1 */
total_collections: number;
@@ -1633,6 +1695,7 @@ export interface components {
slug: string;
/** @example Old fashioned */
name: string;
+ short_ingredients?: string[];
};
CocktailExplore: {
bar?: components["schemas"]["BarBasic"];
@@ -1847,6 +1910,23 @@ export interface components {
/** @example 20 */
dilution_percentage: number;
};
+ CocktailPrice: {
+ /**
+ * @description Number of ingredients that are missing defined prices in this category
+ * @example 1
+ */
+ missing_prices_count: number;
+ price_category: components["schemas"]["PriceCategory"];
+ /** @description Total cocktail price, sum of `price_per_pour` amounts */
+ total_price: components["schemas"]["Price"];
+ prices_per_ingredient: {
+ ingredient: components["schemas"]["IngredientBasic"];
+ /** @description Price per 1 unit of ingredient amount */
+ price_per_amount: components["schemas"]["Price"];
+ /** @description Price per cocktail ingredient part */
+ price_per_pour: components["schemas"]["Price"];
+ }[];
+ };
CocktailRequest: {
/** @example Cocktail name */
name: string;
@@ -3318,7 +3398,7 @@ export interface operations {
specific_ingredients?: string;
ignore_ingredients?: string;
};
- /** @description Sort by attributes. Available attributes: `name`, `created_at`, `average_rating`, `user_rating`, `abv`, `total_ingredients`, `missing_ingredients`, `favorited_at`. */
+ /** @description Sort by attributes. Available attributes: `name`, `created_at`, `average_rating`, `user_rating`, `abv`, `total_ingredients`, `missing_ingredients`, `missing_bar_ingredients`, `favorited_at`. */
sort?: string;
/** @description Include additional relationships. Available relations: `glass`, `method`, `user`, `navigation`, `utensils`, `createdUser`, `updatedUser`, `images`, `tags`, `ingredients.ingredient`, `ratings`. */
include?: string;
@@ -3864,6 +3944,53 @@ export interface operations {
};
};
};
+ getCocktailPrices: {
+ parameters: {
+ query?: never;
+ header?: never;
+ path: {
+ /** @description Database id or slug of a resource */
+ id: string;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Successful response */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": {
+ data: components["schemas"]["CocktailPrice"][];
+ };
+ };
+ };
+ /** @description You are not authorized for this action. */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": {
+ data?: components["schemas"]["APIError"];
+ };
+ };
+ };
+ /** @description Resource record not found. */
+ 404: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": {
+ data?: components["schemas"]["APIError"];
+ };
+ };
+ };
+ };
+ };
"14008654b6c5780b9e826e4e2fcf237a": {
parameters: {
query?: {
@@ -5992,6 +6119,43 @@ export interface operations {
};
};
};
+ "69581b120488a658b86369819bd257e0": {
+ parameters: {
+ query?: {
+ /** @description Database id of a bar. Required if you are not using `Bar-Assistant-Bar-Id` header. */
+ bar_id?: number;
+ };
+ header?: {
+ /** @description Database id of a bar. Required if you are not using `bar_id` query string. */
+ "Bar-Assistant-Bar-Id"?: number;
+ };
+ path?: never;
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Successful response */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "text/csv": string;
+ };
+ };
+ /** @description You are not authorized for this action. */
+ 403: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": {
+ data?: components["schemas"]["APIError"];
+ };
+ };
+ };
+ };
+ };
"8b1d23cbbf81842599e3e9463477cb58": {
parameters: {
query?: {
@@ -7155,6 +7319,56 @@ export interface operations {
};
};
};
+ "40813734b16874942a79324150fb3dd1": {
+ parameters: {
+ query?: {
+ /** @description Set current page number */
+ page?: number;
+ /** @description Set number of results per page */
+ per_page?: number;
+ };
+ header?: never;
+ path: {
+ /** @description Database id of a resource */
+ id: number;
+ };
+ cookie?: never;
+ };
+ requestBody?: never;
+ responses: {
+ /** @description Successful response */
+ 200: {
+ headers: {
+ [name: string]: unknown;
+ };
+ content: {
+ "application/json": {
+ data?: components["schemas"]["CocktailBasic"][];
+ links?: {
+ first?: string | null;
+ last?: string | null;
+ prev?: string | null;
+ next?: string | null;
+ };
+ meta?: {
+ current_page?: number;
+ from?: number;
+ last_page?: number;
+ links?: {
+ url?: string;
+ label?: string;
+ active?: boolean;
+ }[];
+ path?: string;
+ per_page?: number;
+ to?: number;
+ total?: number;
+ };
+ };
+ };
+ };
+ };
+ };
ea114c1013eabd71064b7b33513d13cd: {
parameters: {
query?: {
diff --git a/src/assets/dialog.css b/src/assets/dialog.css
index a953250a..f068ec00 100644
--- a/src/assets/dialog.css
+++ b/src/assets/dialog.css
@@ -47,7 +47,8 @@
outline: none;
pointer-events: auto;
contain: layout;
- background-color: var(--clr-gray-50);
+ /* background-color: var(--clr-gray-50); */
+ background-color: #fcf9fb;
border-top: 2px solid #fff;
padding: var(--dialog-padding);
margin: auto;
diff --git a/src/assets/forms.css b/src/assets/forms.css
index fe0c2959..5d2be197 100644
--- a/src/assets/forms.css
+++ b/src/assets/forms.css
@@ -46,7 +46,8 @@
--form-clr-text: var(--clr-gray-800);
--form-clr-bg: #fff;
--form-clr-bg-focus: #fff;
- --form-clr-border: var(--clr-gray-100);
+ /* --form-clr-border: var(--clr-gray-100); */
+ --form-clr-border: #ece6ea;
--form-clr-border-focus: var(--clr-gray-800);
--form-clr-placeholder: var(--clr-gray-500);
-webkit-appearance: none;
diff --git a/src/components/Calculator/CocktailPriceCalculator.vue b/src/components/Calculator/CocktailPriceCalculator.vue
new file mode 100644
index 00000000..c46a4e8e
--- /dev/null
+++ b/src/components/Calculator/CocktailPriceCalculator.vue
@@ -0,0 +1,94 @@
+
+
+ {{ $t('price.price') }}
+ {{ UnitHandler.formatPrice(parseFloat(finalPrice.price), finalPrice.currency) }}
+
+
Prices are categorized by bar price categories. If price category is missing, the ingredients don't have a price in that category. If there are multiple prices in category, the minimum price is used. Keep in mind that the price is just an estimate and might not be accurate.
++ {{ $t('menu.add-shelf-cocktails') }} + · + {{ $t('menu.export') }} +
{{ $t('menu.remove-category') }} + · + {{ $t('menu.clear-category') }}