Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Manage basket addition from Alias #382 #1021

Merged
merged 14 commits into from
Feb 26, 2024
26 changes: 24 additions & 2 deletions src/routes/(app)/cart/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import { oneMaxPerLine } from '$lib/types/Product.js';
import { UrlDependency } from '$lib/types/UrlDependency.js';
import CmsDesign from '$lib/components/CmsDesign.svelte';
import { POS_ROLE_ID, SUPER_ADMIN_ROLE_ID } from '$lib/types/User';

export let data;

Expand All @@ -40,7 +41,8 @@
},
vatProfiles: data.vatProfiles
});

let alias = '';
let formAlias: HTMLFormElement;
const { t, locale, countryName } = useI18n();
</script>

Expand Down Expand Up @@ -68,7 +70,27 @@
{/if}
<div class="w-full rounded-xl p-6 flex flex-col gap-6 body-mainPlan border-gray-300">
<h1 class="page-title body-title">{t('cart.items')}</h1>

{#if data.roleId === POS_ROLE_ID || data.roleId === SUPER_ADMIN_ROLE_ID}
ithiame marked this conversation as resolved.
Show resolved Hide resolved
<form
action="/product/{alias}?/addToCart"
method="post"
class="flex flex-col gap-2"
bind:this={formAlias}
ithiame marked this conversation as resolved.
Show resolved Hide resolved
>
<div class="gap-4 flex flex-col md:flex-row">
<label class="form-label w-[20em]">
Fill product alias
<input
class="form-input"
type="text"
name="alias"
bind:value={alias}
on:change={() => formAlias.submit()}
/>
</label>
</div>
</form>
{/if}
{#if errorMessage && !errorProductId}
<p class="text-red-600">{errorMessage}</p>
{/if}
Expand Down
55 changes: 45 additions & 10 deletions src/routes/(app)/product/[id]/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import type { RequestEvent } from './$types';
import { DEFAULT_MAX_QUANTITY_PER_ORDER, type Product } from '$lib/types/Product';
import { z } from 'zod';
import { runtimeConfig } from '$lib/server/runtime-config';
import { addToCartInDb } from '$lib/server/cart';
import { addToCartInDb, getCartFromDb } from '$lib/server/cart';
import { CURRENCIES, parsePriceAmount } from '$lib/types/Currency';
import { userIdentifier, userQuery } from '$lib/server/user';
import { POS_ROLE_ID } from '$lib/types/User';
import { cmsFromContent } from '$lib/server/cms';
import { amountOfProductReserved } from '$lib/server/product';
import type { Cart } from '$lib/types/Cart';

export const load = async ({ params, locals }) => {
const product = await collections.products.findOne<
Expand Down Expand Up @@ -119,34 +121,54 @@ export const load = async ({ params, locals }) => {
};

async function addToCart({ params, request, locals }: RequestEvent) {
const product = await collections.products.findOne({ _id: params.id });

if (!product) {
throw error(404, 'Product not found');
}
const product = await collections.products.findOne({
$or: [{ _id: params.id }, { 'alias.0': params.id }, { 'alias.1': params.id }]
ithiame marked this conversation as resolved.
Show resolved Hide resolved
});

const formData = await request.formData();
const { quantity, customPriceAmount, customPriceCurrency, deposit } = z
const { quantity, customPriceAmount, customPriceCurrency, deposit, alias } = z
.object({
quantity: z
.number({ coerce: true })
.int()
.min(1)
.max(product.maxQuantityPerOrder || DEFAULT_MAX_QUANTITY_PER_ORDER)
.max((product && product.maxQuantityPerOrder) || DEFAULT_MAX_QUANTITY_PER_ORDER)
ithiame marked this conversation as resolved.
Show resolved Hide resolved
.default(1),
customPriceAmount: z
.string()
.regex(/^\d+(\.\d+)?$/)
.optional(),
customPriceCurrency: z.enum([CURRENCIES[0], ...CURRENCIES.slice(1)]).optional(),
deposit: z.enum(['partial', 'full']).optional()
deposit: z.enum(['partial', 'full']).optional(),
alias: z.string().optional()
ithiame marked this conversation as resolved.
Show resolved Hide resolved
})
.parse({
quantity: formData.get('quantity') || undefined,
customPriceAmount: formData.get('customPriceAmount') || undefined,
customPriceCurrency: formData.get('customPriceCurrency') || undefined,
deposit: formData.get('deposit') || undefined
deposit: formData.get('deposit') || undefined,
alias: formData.get('alias') || undefined
});
if (!product && alias) {
throw redirect(303, request.headers.get('referer') || 'cart');
}
if (product && product.availableDate && !product.preorder && product.availableDate > new Date()) {
throw redirect(303, request.headers.get('referer') || 'cart');
}
const cart = await getCartFromDb({ user: userIdentifier(locals) });
if (product) {
const availableAmount = await computeAvailableAmount(product, cart);
if (availableAmount <= 0) {
throw redirect(303, request.headers.get('referer') || 'cart');
}
}

if (product && product.availableDate && !product.preorder && product.availableDate > new Date()) {
throw redirect(303, request.headers.get('referer') || 'cart');
}
if (!product) {
throw error(404, 'Product not found');
}
const customPrice =
customPriceAmount && customPriceCurrency
? {
Expand All @@ -159,6 +181,7 @@ async function addToCart({ params, request, locals }: RequestEvent) {
...(product.payWhatYouWant && { customPrice }),
deposit: deposit === 'partial'
});
throw redirect(303, request.headers.get('referer') || 'cart');
ithiame marked this conversation as resolved.
Show resolved Hide resolved
}

export const actions = {
Expand All @@ -170,3 +193,15 @@ export const actions = {

addToCart
};

async function computeAvailableAmount(product: Product, cart: Cart): Promise<number> {
return !product.stock
? Infinity
: product.stock.total -
(await amountOfProductReserved(product._id, {
exclude: {
sessionId: cart.user.sessionId,
npub: cart.user.npub
}
}));
}
Loading