diff --git a/src/lib/components/Table/TableHeader.svelte b/src/lib/components/Table/TableHeader.svelte index 96eb704d..0d25ba3d 100644 --- a/src/lib/components/Table/TableHeader.svelte +++ b/src/lib/components/Table/TableHeader.svelte @@ -19,7 +19,7 @@ class="cursor-pointer select-none text-white font-semibold text-sm whitespace-nowrap {column.align === 'right' ? 'text-end' - : ''}" + : 'text-start'}" > {column.label} {@html SortIcon({ sortOrder: sortOrders[column.key].order })} diff --git a/src/routes/economic-calendar/+page.svelte b/src/routes/economic-calendar/+page.svelte index 822df817..b9c7889d 100644 --- a/src/routes/economic-calendar/+page.svelte +++ b/src/routes/economic-calendar/+page.svelte @@ -5,12 +5,15 @@ import ArrowLogo from "lucide-svelte/icons/move-up-right"; import * as DropdownMenu from "$lib/components/shadcn/dropdown-menu/index.js"; import { Button } from "$lib/components/shadcn/button/index.js"; + import TableHeader from "$lib/components/Table/TableHeader.svelte"; + import { onMount } from "svelte"; import { page } from "$app/stores"; export let data; let rawData; + let filterList = []; let weekdayFiltered = []; let weekday; // Added declaration @@ -23,14 +26,18 @@ let previousMax = false; let nextMax = false; let searchQuery = ""; + let sortMode = false; $: testList = []; $: economicCalendar = data?.getEconomicCalendar; $: daysOfWeek = getDaysOfWeek(currentWeek); $: formattedWeekday = daysOfWeek.map((day) => format(day.date, "EEE, MMM d")); $: { - weekday = getWeekdayData(economicCalendar, daysOfWeek); - rawData = weekday; + if (!sortMode) { + weekday = getWeekdayData(economicCalendar, daysOfWeek); + rawData = weekday; + } + // Reapply filters whenever weekday data changes if (filterList.length > 0 && syncWorker) { loadWorker(); @@ -75,6 +82,7 @@ const handleMessage = (event) => { weekdayFiltered = event.data?.finalData?.output ?? []; + originalData = weekdayFiltered; }; const loadWorker = async () => { @@ -196,6 +204,104 @@ saveRules(); } + + let columns = [ + { key: "time", label: "Time", align: "left" }, + { key: "country", label: "Country", align: "left" }, + { key: "event", label: "Event", align: "left" }, + { key: "actual", label: "Actual", align: "right" }, + { key: "consensus", label: "Forecast", align: "right" }, + { key: "prior", label: "Previous", align: "right" }, + { key: "importance", label: "Importance", align: "right" }, + ]; + + let sortOrders = { + time: { order: "none", type: "string" }, + country: { order: "none", type: "string" }, + event: { order: "none", type: "string" }, + actual: { order: "none", type: "number" }, + consensus: { order: "none", type: "number" }, + prior: { order: "none", type: "number" }, + importance: { order: "none", type: "number" }, + }; + + const sortData = (key) => { + sortMode = true; + for (const k in sortOrders) { + if (k !== key) { + sortOrders[k].order = "none"; + } + } + + // Cycle through 'none', 'asc', 'desc' for the clicked key + const orderCycle = ["none", "asc", "desc"]; + const currentOrderIndex = orderCycle.indexOf( + sortOrders[key]?.order || "none", + ); + sortOrders[key] = { + ...(sortOrders[key] || {}), + order: orderCycle[(currentOrderIndex + 1) % orderCycle.length], + }; + const sortOrder = sortOrders[key]?.order; + + // Reset to original data when 'none' and stop further sorting + if (sortOrder === "none") { + sortMode = false; + return; + } + + // Generic comparison function + const compareValues = (a, b) => { + const { type } = sortOrders[key]; + let valueA, valueB; + + switch (type) { + case "date": + valueA = new Date(a[key]); + valueB = new Date(b[key]); + break; + case "rating": + case "string": + // Retrieve values + valueA = a[key]; + valueB = b[key]; + + // Handle null or undefined values, always placing them at the bottom + if (valueA == null && valueB == null) { + return 0; // Both are null/undefined, no need to change the order + } else if (valueA == null) { + return 1; // null goes to the bottom + } else if (valueB == null) { + return -1; // null goes to the bottom + } + + // Convert the values to uppercase for case-insensitive comparison + valueA = valueA?.toUpperCase(); + valueB = valueB?.toUpperCase(); + + // Perform the sorting based on ascending or descending order + return sortOrder === "asc" + ? valueA?.localeCompare(valueB) + : valueB?.localeCompare(valueA); + case "number": + default: + valueA = parseFloat(a[key]); + valueB = parseFloat(b[key]); + break; + } + + if (sortOrder === "asc") { + return valueA < valueB ? -1 : valueA > valueB ? 1 : 0; + } else { + return valueA > valueB ? -1 : valueA < valueB ? 1 : 0; + } + }; + + // Sort and update the originalData and stockList + weekday[selectedWeekday] = [...rawData[selectedWeekday]].sort( + compareValues, + ); + }; @@ -270,7 +376,7 @@ on:click={() => changeWeek("previous")} class="{previousMax ? 'opacity-80' - : ''} hidden sm:flex h-16 w-48 cursor-pointer border m-auto flex bg-[#27272A] border border-gray-600 mb-3" + : ''} hidden sm:flex h-16 w-48 cursor-pointer border m-auto flex bg-primary border border-gray-600 mb-3" > changeWeek("next")} class="{nextMax ? 'opacity-80' - : ''} hidden sm:flex h-16 w-48 cursor-pointer border m-auto flex bg-[#27272A] border border-gray-600 mb-3" + : ''} hidden sm:flex h-16 w-48 cursor-pointer border m-auto flex bg-primary border border-gray-600 mb-3" > Filter Country {#each testList.length > 0 && searchQuery?.length > 0 ? testList : searchQuery?.length > 0 && testList?.length === 0 ? [] : listOfRelevantCountries as item} - +
{#each [1, 2, 3] as i} - +