Increase hit target for dropdown

Add CartRecord type
Remove OOP style Promises from Contact
Add contact reason dropdown
The usual SCSS changes and adjustments
This commit is contained in:
Michał 2024-05-16 13:32:11 +01:00
parent 865654de87
commit c908a544aa
7 changed files with 125 additions and 51 deletions

View file

@ -6,12 +6,10 @@
</script>
<div class="dropdown" class:open={open}>
<div class="dropdown-header">
<p>{name}</p>
<button on:click={() => { open = !open }}>
<CaretDown />
</button>
</div>
<button class="dropdown-header" on:click={() => { open = !open }}>
<span class="dropdown-text">{name}</span>
<span class="dropdown-button"><CaretDown /></span>
</button>
<div class="dropdown-content">
<slot></slot>
</div>
@ -28,6 +26,8 @@
.dropdown-header {
padding: $spacing-normal;
width: 100%;
position: relative;
display: flex;
@ -35,12 +35,15 @@
justify-content: space-between;
align-items: center;
p {
border: 0 solid transparent;
background-color: transparent;
.dropdown-text {
font-size: $font-size-h6;
font-weight: $font-weight-bold;
}
button {
.dropdown-button {
padding: 0;
height: 100%;
@ -62,9 +65,13 @@
color: $color-on-light;
transition: transform 0.1s ease-in-out;
}
&:hover {
&:hover, &:focus-visible {
.dropdown-button {
color: $color-primary;
outline: 0 solid transparent;
transform: rotate(-15deg);
}
}
}
@ -76,11 +83,15 @@
&.open {
.dropdown-header {
//padding: $spacing-normal $spacing-normal $spacing-small;
button {
.dropdown-button {
transform: rotate(-180deg);
}
&:hover, &:focus-visible {
.dropdown-button {
transform: rotate(calc(-180deg + 15deg));
}
}
}
.dropdown-content {
display: block;

View file

@ -1,24 +1,23 @@
import { type Writable, get, writable } from "svelte/store";
import { type CartItem, type Item } from "./types";
import { type CartRecord, type CartItem, type Item } from "./types";
import { getItemByUUID, postVerifyCart } from "./test-api";
function createCartStore() {
let loaded = false;
const cart: Writable<Record<string, CartItem>> = writable({});
const cart: Writable<CartRecord> = writable({});
async function init() {
let localData: Record<string, CartItem> = {};
async function init(): Promise<void> {
let localData: CartRecord = {};
try {
localData = JSON.parse(localStorage.getItem("basket")) || {};
} catch {
console.error("Local Cart data fucked");
console.error("Local Cart data could not be parsed");
}
try {
const newData: Record<string, CartItem> =
await postVerifyCart(localData);
const newData: CartRecord = await postVerifyCart(localData);
cart.set(newData);
} catch (error) {
console.error("Could not load basket:", error);
@ -28,18 +27,16 @@ function createCartStore() {
}
async function addToCart(uuid: string, amount: number) {
if (!loaded) {
return;
}
if (!loaded) return;
if (get(cart)[uuid] !== undefined) {
cart.update((cart: Record<string, CartItem>) => {
cart.update((cart: CartRecord) => {
cart[uuid].amount += amount;
return cart;
});
} else {
await getItemByUUID(uuid).then((data: Item) => {
cart.update((cart: Record<string, CartItem>) =>
cart.update((cart: CartRecord) =>
Object.assign({}, cart, {
[uuid]: { uuid, amount, data },
})
@ -47,13 +44,9 @@ function createCartStore() {
});
}
cart.update((cart: Record<string, CartItem>) => {
if (cart[uuid].amount <= 0) {
delete cart[uuid]; // skipcq: JS-0320
} else if (cart[uuid].amount > 99) {
cart[uuid].amount = 99; // skipcq: JS-0320
}
cart.update((cart: CartRecord) => {
if (cart.uuid.amount <= 0) delete cart.uuid;
if (cart.uuid.amount > 99) cart.uuid.amount = 99;
return cart;
});
}
@ -82,12 +75,10 @@ function createCartStore() {
return totalCartPrice;
}
function removeByUUID(uuid: string) {
if (!loaded) {
return;
}
function removeByUUID(uuid: string): void {
if (!loaded) return;
cart.update((cart) => {
cart.update((cart: CartRecord) => {
delete cart[uuid]; // skipcq: JS-0320
return cart;
});
@ -110,7 +101,7 @@ const Cart = createCartStore();
export const cartLoaded = Cart.init();
// Make sure to update localstorage on any changes
Cart.subscribe((value) => {
Cart.subscribe((value: CartRecord) => {
localStorage.setItem("basket", JSON.stringify(value));
});

View file

@ -71,12 +71,14 @@ export async function getItemByUUID(uuid: string): Promise<Item> {
export async function postContactEmail(
name: string,
email: string,
reason: string,
message: string
): Promise<string> {
await fakeDelay(200);
if (!name) throw new Error("Name missing");
if (!email) throw new Error("Email missing");
if (!reason) throw new Error("Reason missing");
if (!message) throw new Error("Message missing");
if (message.length < 150) throw new Error("Message FUCKED");

View file

@ -21,6 +21,8 @@ export type CartItem = {
data: Item;
};
export type CartRecord = Record<string, CartItem>
export type JSONResponse = {
data?: {
item: Item[]; // Todo Make this not just item type

View file

@ -1,5 +1,5 @@
<script lang="ts">
import { PaperPlaneRight, SealWarning, SealCheck } from "phosphor-svelte";
import { PaperPlaneRight, SealWarning, SealCheck, CaretDown } from "phosphor-svelte";
import { postContactEmail } from "../lib/test-api";
import { expandOnTyping } from "../lib/utils";
@ -11,27 +11,28 @@
let name = "";
let email = "";
let reason = "";
let message = "";
let nameValid = true;
let emailValid = true;
let reasonValid = true;
let messageValid = false;
function validateName() { nameValid = name.length > 1 }
function validateEmail() { emailValid = email.length > 1 }
function validateReason() { reasonValid = reason != "" }
function validateMessage() { messageValid = message.length > minMessageLength }
function onSubmit() {
nameValid = true;
emailValid = true;
formMessage = postContactEmail(name, email, message)
.catch((error) => {
validateName();
validateEmail();
validateMessage();
throw error;
});
try {
formMessage = postContactEmail(name, email, reason, message)
} catch (error) {
validateName();
validateEmail();
validateReason();
validateMessage();
}
}
</script>
@ -96,13 +97,41 @@
</div>
<div class="spacer half" />
<!-- ToDo: Add dropdown for issue type, such as Technical, Order, Account, or other -->
<div class="form-element">
<label class="form-label" for="reason">Contact Reason</label>
<div class="select-container">
<select
bind:value={reason}
on:blur={validateReason}
on:input={validateReason}
class="form-input"
id="reason"
name="reason"
>
<option value="general">General Enquiry</option>
<option value="technical">Technical/Website</option>
<option value="order">Order</option>
<option value="booking">Booking</option>
</select>
<div class="select-arrow">
<CaretDown />
</div>
</div>
<span class="form-notice error">
{#if !reasonValid}
You must provide a reason for contact
{/if}
</span>
</div>
<div class="spacer half" />
<div class="form-element">
<label class="form-label" for="message">Message</label>
<textarea
bind:value={message}
on:input={validateMessage}
on:blur={validateMessage}
use:expandOnTyping
rows="1"
cols="50"
@ -146,6 +175,37 @@
overflow: hidden;
}
.select-container{
width: max-content;
position: relative;
> select {
width: 200px;
appearance: none;
}
> .select-arrow {
height: 100%;
position: absolute;
top: 0;
right: $spacing-small;
display: flex;
justify-content: center;
align-items: center;
transition: transform 0.1s ease-in-out;
pointer-events: none;
}
&:hover {
> .select-arrow {
transform: translateY(2px);
}
}
}
button {
padding: 0 $spacing-normal;

View file

@ -170,6 +170,10 @@
margin-left: $spacing-normal;
width: 100%;
position: relative;
> h2, p {
text-align: right;
}
}
#filter {
@ -222,6 +226,10 @@
#menu-list {
margin-left: 0;
margin-top: $spacing-normal;
> h2, p {
text-align: left;
}
}
}
</style>

View file

@ -21,7 +21,7 @@
font-family: $font-family;
font-size: $font-size-p;
border: 1px solid rgba($color-dark, 0.2);
border: 1px solid $color-light;
border-radius: $border-radius-normal;
background-color: $color-light;
color: $color-on-light;