diff --git a/signal-desktop-keyring.gpg b/signal-desktop-keyring.gpg new file mode 100644 index 00000000..b5e68a04 Binary files /dev/null and b/signal-desktop-keyring.gpg differ diff --git a/src/assets/categoryIcons/holiday.svg b/src/assets/categoryIcons/holiday.svg index 0d4e6143..448d4465 100644 --- a/src/assets/categoryIcons/holiday.svg +++ b/src/assets/categoryIcons/holiday.svg @@ -1,2 +1,46 @@ - - + + + + + + + + + + + + + + + + diff --git a/src/components/posts/ClientViewProviderPosts.tsx b/src/components/posts/ClientViewProviderPosts.tsx index d836e432..daad472d 100644 --- a/src/components/posts/ClientViewProviderPosts.tsx +++ b/src/components/posts/ClientViewProviderPosts.tsx @@ -5,72 +5,77 @@ import supabase from "../../lib/supabaseClient"; import { ui } from "../../i18n/ui"; import type { uiObject } from "../../i18n/uiType"; import { getLangFromUrl, useTranslations } from "../../i18n/utils"; -import stripe from "@lib/stripe"; +import stripe from "@lib/stripe"; const lang = getLangFromUrl(new URL(window.location.href)); //get the categories from the language files so they translate with changes in the language picker const values = ui[lang] as uiObject; -const productCategories = values.productCategoryInfo.categories; +const productCategories = values.subjectCategoryInfo.subjects; interface ProviderPost { - user_id: string; - content: string; - id: number; - //TODO: update this to allow a list of Subjects - subject: string; - title: string; - seller_name: string; - major_municipality: string; - image_urls: string; - price: number; - price_id: string; - quantity: number; - product_id: string; + user_id: string; + content: string; + id: number; + image_url: string | undefined; + seller_img: string | undefined; + //TODO: update this to allow a list of Subjects + subject: Array; + title: string; + seller_name: string; + major_municipality: string; + image_urls: string; + price: number; + price_id: string; + quantity: number; + product_id: string; } interface Props { - id: string | undefined; + id: string | undefined; } export const ClientViewProviderPosts: Component = (props) => { - const [posts, setPosts] = createSignal>([]); + const [posts, setPosts] = createSignal>([]); - createEffect(async () => { - const { data, error } = await supabase - .from("sellerposts") - .select("*") - .eq("seller_id", props.id); - if (!data) { - alert("No posts available."); - } - if (error) { - console.log("supabase error: " + error.message); - } else { - const newItems = await Promise.all( - data?.map(async (item) => { - productCategories.forEach((productCategories) => { - if (item.product_subject.toString() === productCategories.id) { - item.subject = productCategories.name; - } - }); - delete item.product_subject; + createEffect(async () => { + const { data, error } = await supabase + .from("sellerposts") + .select("*") + .eq("seller_id", props.id); + if (!data) { + alert("No posts available."); + } + if (error) { + console.log("supabase error: " + error.message); + } else { + const newItems = await Promise.all( + data?.map(async (item) => { + productCategories.forEach((productCategories) => { + item.product_subject.map((productSubject: string) => { + if (productSubject === productCategories.id) { + item.subject.push(productCategories.name); + console.log(productCategories.name); + } + }); + }); + delete item.product_subject; - if (item.price_id !== null) { - const priceData = await stripe.prices.retrieve(item.price_id); - item.price = priceData.unit_amount! / 100; - } - return item; - })) - ; - setPosts(data); - console.log("Posts") - console.log(posts()) - } - }); - return ( -
- -
- ); + if (item.price_id !== null) { + const priceData = await stripe.prices.retrieve(item.price_id); + item.price = priceData.unit_amount! / 100; + } + return item; + }), + ); + setPosts(data); + console.log("Posts"); + console.log(posts()); + } + }); + return ( +
+ +
+ ); }; diff --git a/src/components/posts/CreateNewPost.tsx b/src/components/posts/CreateNewPost.tsx index 3b8a7ef1..401d2c9a 100644 --- a/src/components/posts/CreateNewPost.tsx +++ b/src/components/posts/CreateNewPost.tsx @@ -138,6 +138,9 @@ export const CreateNewPost: Component = () => { const [selectedTaxCode, setSelectedTaxCode] = createSignal(); + productCategoryData.subjects.map((item) => + setSubjects([...subjects(), { id: Number(item.id), subject: item.name }]), + ); onMount(() => { window.addEventListener("storage", (event) => { if (event.key === "theme") { @@ -191,11 +194,14 @@ export const CreateNewPost: Component = () => { /^txcd_1.*/.test(taxCode.id) && //Not in our filter list !Array.from(excludeTaxCodes).some((excludeTaxCode) => - excludeTaxCode.test(taxCode.id) + excludeTaxCode.test(taxCode.id), ) ) { let taxCodeOption = new Option(taxCode.name, taxCode.id); - taxCodeOption.setAttribute("data-description", taxCode.description); + taxCodeOption.setAttribute( + "data-description", + taxCode.description, + ); taxCodeOptions.push(taxCodeOption); } }); diff --git a/src/components/posts/CreateStripeProductPrice.tsx b/src/components/posts/CreateStripeProductPrice.tsx index 979ccc12..93305054 100644 --- a/src/components/posts/CreateStripeProductPrice.tsx +++ b/src/components/posts/CreateStripeProductPrice.tsx @@ -16,7 +16,7 @@ async function postStripeData(stripeData: FormData) { }); const data = await response.json(); if (data.redirect) { - alert(data.message); + alert(data.message); window.location.href = `/${lang}` + data.redirect; } return data; @@ -35,7 +35,11 @@ interface Props { export const CreateStripeProductPrice: Component = (props: Props) => { const [stripeData, setStripeData] = createSignal(); const [response] = createResource(stripeData, postStripeData); - async function createProduct(name: string, description: string, tax_code: string) { + async function createProduct( + name: string, + description: string, + tax_code: string, + ) { return stripe.products.create({ name: name, description: description, @@ -52,8 +56,12 @@ export const CreateStripeProductPrice: Component = (props: Props) => { } async function createPriceAndProduct() { - console.log("Stripe Tax Code: " + props.tax_code) - const product = await createProduct(props.name, props.description, props.tax_code); + console.log("Stripe Tax Code: " + props.tax_code); + const product = await createProduct( + props.name, + props.description, + props.tax_code, + ); const price = await createPrice(product, props.price); const stripeData = new FormData(); stripeData.append("price_id", price.id); diff --git a/src/components/posts/FullPostView.tsx b/src/components/posts/FullPostView.tsx index dbdb3323..62be1a34 100644 --- a/src/components/posts/FullPostView.tsx +++ b/src/components/posts/FullPostView.tsx @@ -3,9 +3,9 @@ import { createSignal, createEffect, Show } from "solid-js"; import supabase from "../../lib/supabaseClient"; import { DeletePostButton } from "../posts/DeletePostButton"; import type { AuthSession } from "@supabase/supabase-js"; -import { ui } from '../../i18n/ui' -import type { uiObject } from '../../i18n/uiType'; -import { getLangFromUrl, useTranslations } from '../../i18n/utils'; +import { ui } from "../../i18n/ui"; +import type { uiObject } from "../../i18n/uiType"; +import { getLangFromUrl, useTranslations } from "../../i18n/utils"; import { windowPersistentEvents } from "@nanostores/persistent"; import SocialModal from "./SocialModal"; @@ -13,13 +13,13 @@ const lang = getLangFromUrl(new URL(window.location.href)); const t = useTranslations(lang); //get the categories from the language files so they translate with changes in the language picker -const values = ui[lang] as uiObject -const productCategories = values.productCategoryInfo.categories +const values = ui[lang] as uiObject; +const productCategories = values.subjectCategoryInfo.subjects; interface Post { content: string; id: number; - subject: string; + product_subject: Array; title: string; seller_name: string; major_municipality: string; @@ -45,7 +45,7 @@ export const ViewFullPost: Component = (props) => { createEffect(() => { if (props.id === undefined) { - location.href = `/${lang}/404` + location.href = `/${lang}/404`; } else if (props.id) { setSession(User.session); fetchPost(+props.id); @@ -63,41 +63,41 @@ export const ViewFullPost: Component = (props) => { if (error) { console.log(error); } else if (data[0] === undefined) { - alert(t('messages.noPost')); - location.href = `/${lang}/services` + alert(t("messages.noPost")); + location.href = `/${lang}/services`; } else { data?.map(async (item) => { - productCategories.forEach(productCategories => { + productCategories.forEach((productCategories) => { if (item.product_subject.toString() === productCategories.id) { - item.subject = productCategories.name + item.subject = productCategories.name; } - }) - delete item.product_subject - item.seller_url = `/${lang}/provider/${item.seller_id}` - }) + }); + delete item.product_subject; + item.seller_url = `/${lang}/provider/${item.seller_id}`; + }); setPost(data[0]); } } catch (error) { console.log(error); } } else { - alert(t('messages.signIn')) - location.href = `/${lang}/login` + alert(t("messages.signIn")); + location.href = `/${lang}/login`; } - } + }; createEffect(async () => { if (post() !== undefined) { if (post()?.image_urls === undefined || post()?.image_urls === null) { } else { - await downloadImages(post()?.image_urls!) + await downloadImages(post()?.image_urls!); } } - }) + }); const downloadImages = async (image_Urls: string) => { try { - const imageUrls = image_Urls.split(','); + const imageUrls = image_Urls.split(","); imageUrls.forEach(async (imageUrl: string) => { const { data, error } = await supabase.storage .from("post.image") @@ -107,21 +107,21 @@ export const ViewFullPost: Component = (props) => { } const url = URL.createObjectURL(data); setPostImages([...postImages(), url]); - }) + }); } catch (error) { - console.log(error) + console.log(error); } - } + }; let slideIndex = 1; - showSlide(slideIndex) + showSlide(slideIndex); function moveSlide(n: number) { - showSlide(slideIndex += n); + showSlide((slideIndex += n)); } function currentSlide(n: number) { - showSlide(slideIndex = n); + showSlide((slideIndex = n)); } function showSlide(n: number) { @@ -160,165 +160,241 @@ export const ViewFullPost: Component = (props) => { dots[slideIndex - 1].classList.add(`bg-white`); dots[slideIndex - 1].classList.add(`dark:bg-gray-600`); } - } - const twitterUrl = "https://twitter.com/intent/tweet?text=Check%20this%20out%20!"; + const twitterUrl = + "https://twitter.com/intent/tweet?text=Check%20this%20out%20!"; const facebookUrl = "https://www.facebook.com/sharer/sharer.php?u="; const whatsappUrl = "https://wa.me/?text="; const linkTarget = "_top"; const windowOptions = "menubar=yes,status=no,height=300,width=600"; function extractTitleText() { - return document.querySelector('h2')?.innerText; + return document.querySelector("h2")?.innerText; } function extractAnchorLink() { - return document.querySelector('a')?.href; + return document.querySelector("a")?.href; } - + function extractWindowLink() { const currLink = window.location.href; return currLink; } - - function openTwitterWindow(text:any, link:any) { + + function openTwitterWindow(text: any, link: any) { const twitterQuery = `${text} ${link}`; - return window.open(`${twitterUrl} ${twitterQuery}&`, linkTarget, windowOptions); + return window.open( + `${twitterUrl} ${twitterQuery}&`, + linkTarget, + windowOptions, + ); } - function registerShareButton() { extractWindowLink(); - const text= extractTitleText(); + const text = extractTitleText(); const link = extractWindowLink(); - const twitterButton = document.querySelector('#button--twitter'); - twitterButton?.addEventListener('click', () => openTwitterWindow(text, link)) + const twitterButton = document.querySelector("#button--twitter"); + twitterButton?.addEventListener("click", () => + openTwitterWindow(text, link), + ); } - function openFacebookWindow(text:any, link:any) { + function openFacebookWindow(text: any, link: any) { const currPage = extractWindowLink(); - const testLink = "https://www.facebook.com/sharer/sharer.php?u=" + encodeURIComponent(currPage); - window.open("https://www.facebook.com/sharer/sharer.php?u=" + encodeURIComponent(currPage)+ "&t=" + text, '', 'menubar=yes,toolbar=no,resizable=yes,scrollbars=yes,height=300,width=600'); - console.log("TestLink: ", testLink) - // return false; + const testLink = + "https://www.facebook.com/sharer/sharer.php?u=" + + encodeURIComponent(currPage); + window.open( + "https://www.facebook.com/sharer/sharer.php?u=" + + encodeURIComponent(currPage) + + "&t=" + + text, + "", + "menubar=yes,toolbar=no,resizable=yes,scrollbars=yes,height=300,width=600", + ); + console.log("TestLink: ", testLink); + // return false; } function registerFacebookButton() { extractWindowLink(); const text = extractTitleText(); const link = extractWindowLink(); - const facebookButton = document.querySelector('#button--facebook'); - facebookButton?.addEventListener('click', () => openFacebookWindow(text, link)); + const facebookButton = document.querySelector("#button--facebook"); + facebookButton?.addEventListener("click", () => + openFacebookWindow(text, link), + ); } - function openWhatsappWindow(text:any, link:any) { + function openWhatsappWindow(text: any, link: any) { const currPage = extractWindowLink(); - const testLink = whatsappUrl + "Check%20out%20this%20awesome%20service%20on%20TodoServis! "; - window.open(testLink + encodeURIComponent(currPage), 'menubar=yes,toolbar=no,resizable=yes,scrollbars=yes,height=300,width=600'); - + const testLink = + whatsappUrl + + "Check%20out%20this%20awesome%20service%20on%20TodoServis! "; + window.open( + testLink + encodeURIComponent(currPage), + "menubar=yes,toolbar=no,resizable=yes,scrollbars=yes,height=300,width=600", + ); } function registerWhatsAppButton() { const text = extractTitleText(); const link = extractWindowLink(); - const whatsAppButton = document.querySelector('#button--whatsapp'); - whatsAppButton?.addEventListener('click', () => openWhatsappWindow(text, link)); + const whatsAppButton = document.querySelector("#button--whatsapp"); + whatsAppButton?.addEventListener("click", () => + openWhatsappWindow(text, link), + ); } - + return (
-

+

{post()?.title}

{/* */} - + 0}>
-
+
{`${t('postLabels.image')} + class="block object-contain absolute top-1/2 left-1/2 h-56 -translate-x-1/2 -translate-y-1/2 md:h-96" + alt={`${t("postLabels.image")} 1`} + />
1}> - {postImages().slice(1).map((image: string, index: number) => ( - - ))} + {postImages() + .slice(1) + .map((image: string, index: number) => ( + + ))}
1}> -
+
- {postImages().slice(1).map((image: string, index: number) => ( - - ))} + > + {postImages() + .slice(1) + .map((image: string, index: number) => ( + + ))}
-

{t('postLabels.provider')}{post()?.seller_name}

- {t('postLabels.location')}{post()?.major_municipality}/{post()?.minor_municipality}/ + {t("postLabels.provider")} + + {post()?.seller_name} + +

+

+ {t("postLabels.location")} + {post()?.major_municipality}/{post()?.minor_municipality}/ {post()?.governing_district}

-

{t('postLabels.category')}{post()?.subject}

-
+

+ {t("postLabels.categories")} + {post()?.subject} +

+
- +
- +
); - }; diff --git a/src/components/posts/SocialMediaShares.tsx b/src/components/posts/SocialMediaShares.tsx index bd5a50a2..acb6a1c3 100644 --- a/src/components/posts/SocialMediaShares.tsx +++ b/src/components/posts/SocialMediaShares.tsx @@ -1,24 +1,25 @@ import type { Component } from "solid-js"; import supabase from "../../lib/supabaseClient"; import type { AuthSession } from "@supabase/supabase-js"; -import { ui } from '../../i18n/ui' -import type { uiObject } from '../../i18n/uiType'; -import { getLangFromUrl, useTranslations } from '../../i18n/utils'; -import placeholderImg from '../../assets/userImagePlaceholder.svg'; -import dogLogo from '../../assets/dog-4-svgrepo-com (2).svg' +import { ui } from "../../i18n/ui"; +import type { uiObject } from "../../i18n/uiType"; +import { getLangFromUrl, useTranslations } from "../../i18n/utils"; +import placeholderImg from "../../assets/userImagePlaceholder.svg"; +import dogLogo from "../../assets/dog-4-svgrepo-com (2).svg"; import { windowPersistentEvents } from "@nanostores/persistent"; const lang = getLangFromUrl(new URL(window.location.href)); const t = useTranslations(lang); -const values = ui[lang] as uiObject -const productCategories = values.productCategoryInfo.categories +const values = ui[lang] as uiObject; +const productCategories = values.subjectCategoryInfo.subjects; const xUrl = "https://twitter.com/intent/tweet?text=Check%20this%20out!%20"; const facebookUrl = "https://www.facebook.com/sharer/sharer.php?u="; -const fbMessengerUrl = "fb-messenger://share/?link=" +const fbMessengerUrl = "fb-messenger://share/?link="; const whatsappUrl = "https://wa.me/?text="; -const emailURL = "mailto:?subject=Check this out this service from TodoServis!&body=Check%20out%20this%20service:%20"; +const emailURL = + "mailto:?subject=Check this out this service from TodoServis!&body=Check%20out%20this%20service:%20"; const linkTarget = "_top"; const windowOptions = "menubar=no,status=no,height=300,width=600"; @@ -33,36 +34,39 @@ interface Props { id: string | undefined; } - export const SocialMediaShares: Component = (props) => { - const showSocials = async(e:SubmitEvent) => { + const showSocials = async (e: SubmitEvent) => { e.preventDefault(); const shareBtn = e.currentTarget; - const currSocialsBtnDiv = document.getElementById('socialsBtns' + props.id ) + const currSocialsBtnDiv = document.getElementById("socialsBtns" + props.id); - if(currSocialsBtnDiv?.classList.contains("hidden")) { + if (currSocialsBtnDiv?.classList.contains("hidden")) { currSocialsBtnDiv.classList.remove("hidden"); currSocialsBtnDiv.classList.add("flex"); - } else if(currSocialsBtnDiv?.classList.contains("flex")) { + } else if (currSocialsBtnDiv?.classList.contains("flex")) { currSocialsBtnDiv.classList.remove("flex"); currSocialsBtnDiv.classList.add("hidden"); } else { return; } - } + }; - const currPostLink = `www.todoservis.com/${ lang }/posts/${ props.id }`; + const currPostLink = `www.todoservis.com/${lang}/posts/${props.id}`; const fbShareLink = facebookUrl + currPostLink; - function xShare(e:Event) { + function xShare(e: Event) { e.stopPropagation(); e.preventDefault(); - window.open(xUrl + `www.todoservis.com/${ lang }/posts/${ props.id }`, "_blank", windowOptions); + window.open( + xUrl + `www.todoservis.com/${lang}/posts/${props.id}`, + "_blank", + windowOptions, + ); } - function facebookShare(e:Event) { + function facebookShare(e: Event) { e.stopPropagation(); e.preventDefault(); @@ -73,28 +77,35 @@ export const SocialMediaShares: Component = (props) => { window.open(fbMessengerUrl, "_blank", windowOptions); } - function whatsAppShare(e:Event) { + function whatsAppShare(e: Event) { e.stopPropagation(); e.preventDefault(); - window.open(whatsappUrl + encodeURIComponent(`www.todoservis.com/${ lang }/posts/${ props.id }`), windowOptions); + window.open( + whatsappUrl + + encodeURIComponent(`www.todoservis.com/${lang}/posts/${props.id}`), + windowOptions, + ); } - function emailShare(e:Event) { + function emailShare(e: Event) { e.stopPropagation(); e.preventDefault(); - window.open(emailURL + encodeURIComponent(`www.todoservis.com/${ lang }/posts/${ props.id }`)); + window.open( + emailURL + + encodeURIComponent(`www.todoservis.com/${lang}/posts/${props.id}`), + ); } - function linkShare(e:Event) { + function linkShare(e: Event) { e.stopPropagation(); e.preventDefault(); return navigator.clipboard.writeText(currPostLink); } - function embedShare(e:Event) { + function embedShare(e: Event) { e.stopPropagation(); e.preventDefault(); @@ -107,104 +118,244 @@ export const SocialMediaShares: Component = (props) => { return navigator.share(shareData); } - function textShare(e:Event) { + function textShare(e: Event) { e.stopPropagation(); e.preventDefault(); - let message = "Check%20out%20this%20great%20service%20from%20TodoServis!%20"; + let message = + "Check%20out%20this%20great%20service%20from%20TodoServis!%20"; - window.open("sms:?&body=" + message + currPostLink, "_blank", windowOptions); + window.open( + "sms:?&body=" + message + currPostLink, + "_blank", + windowOptions, + ); } - + return ( -
+
-

{t("socialModal.shareService")}:

- +

+ {t("socialModal.shareService")}:{" "} +

+
- -

{ props.title }

+ +

{props.title}

- +
-
-

{t("socialModal.disclaimer")}

+

+ {t("socialModal.disclaimer")} +

); - -} \ No newline at end of file +}; diff --git a/src/components/posts/ViewProviderPosts.tsx b/src/components/posts/ViewProviderPosts.tsx index 2105361c..b6f1769b 100644 --- a/src/components/posts/ViewProviderPosts.tsx +++ b/src/components/posts/ViewProviderPosts.tsx @@ -13,7 +13,7 @@ const lang = getLangFromUrl(new URL(window.location.href)); //get the categories from the language files so they translate with changes in the language picker const values = ui[lang] as uiObject; -const productCategories = values.productCategoryInfo.categories; +const productCategories = values.subjectCategoryInfo.subjects; // Define the type for the ProviderPost interface interface ProviderPost { @@ -35,7 +35,6 @@ interface ProviderPost { // Get the user session const { data: User, error: UserError } = await supabase.auth.getSession(); - export const ViewProviderPosts: Component = () => { // initialize posts and session const [posts, setPosts] = createSignal>([]); @@ -74,9 +73,9 @@ export const ViewProviderPosts: Component = () => { item.price = priceData.unit_amount! / 100; } return item; - }) + }), ); - console.log(newItems.map(item => item.price)) + console.log(newItems.map((item) => item.price)); setPosts(newItems); } }); @@ -87,9 +86,8 @@ export const ViewProviderPosts: Component = () => {
- +
-
); }; diff --git a/src/components/posts/fetchPosts.ts b/src/components/posts/fetchPosts.ts index bda4ee7f..0d1aa846 100644 --- a/src/components/posts/fetchPosts.ts +++ b/src/components/posts/fetchPosts.ts @@ -1,57 +1,85 @@ -import supabase from '../../lib/supabaseClient'; -import { ui } from '../../i18n/ui'; -import type { uiObject } from '../../i18n/uiType'; +import supabase from "../../lib/supabaseClient"; +import { ui } from "../../i18n/ui"; +import type { uiObject } from "../../i18n/uiType"; import { getLangFromUrl, useTranslations } from "../../i18n/utils"; +import stripe from "@lib/stripe"; const lang = getLangFromUrl(new URL(window.location.href)); const t = useTranslations(lang); -// one giant filter function that includes the logic for all combinations -export async function fetchFilteredPosts(categoryFilters: Array, locationFilters: Array, minorLocationFilters: Array, governingLocationFilters: Array, searchString: string) { +// one giant filter function that includes the logic for all combinations +export async function fetchFilteredPosts( + categoryFilters: Array, + // subjectFilters: Array, + locationFilters: Array, + minorLocationFilters: Array, + governingLocationFilters: Array, + searchString: string, +) { try { - let query = supabase.from("sellerposts").select("*"); - if(categoryFilters.length !== 0) { - query = query.in('product_subject', categoryFilters); - } - if(locationFilters.length !== 0) { - query = query.in('major_municipality', locationFilters); - } - if(minorLocationFilters.length !== 0) { - query = query.in('minor_municipality', minorLocationFilters); - } - if(governingLocationFilters.length !== 0) { - query = query.in('governing_district', governingLocationFilters); - } - if(searchString.length !== 0) { - query = query.textSearch('title_content', searchString); - } + let query = supabase.from("sellerposts").select("*"); + if (categoryFilters.length !== 0) { + query = query.overlaps("product_subject", categoryFilters); + } + if (locationFilters.length !== 0) { + query = query.in("major_municipality", locationFilters); + } + if (minorLocationFilters.length !== 0) { + query = query.in("minor_municipality", minorLocationFilters); + } + if (governingLocationFilters.length !== 0) { + query = query.in("governing_district", governingLocationFilters); + } + if (searchString.length !== 0) { + query = query.textSearch("title_content", searchString); + } - try { - const { data: posts, error } = await query - if(error) { - console.log("supabase error: " + error.message); - } else { - return posts; - } - } catch (e) { - console.error(e); + try { + const { data: posts, error } = await query; + if (error) { + console.log("supabase error: " + error.code + error.message); + } else { + const newItems = await Promise.all( + posts?.map(async (item) => { + if (item.price_id !== null) { + const priceData = await stripe.prices.retrieve(item.price_id); + item.price = priceData.unit_amount! / 100; + } + return item; + }), + ); + console.log(newItems); + return newItems; } - - } catch(e) { - console.error(e) + } catch (e) { + console.error(e); + } + } catch (e) { + console.error(e); } -} +} export async function fetchAllPosts() { try { - const { data: allPosts, error } = await supabase.from("sellerposts").select("*") + const { data: allPosts, error } = await supabase + .from("sellerposts") + .select("*"); - if(error) { + if (error) { console.log("supabase error: " + error.message); } else { - return allPosts + const newItems = await Promise.all( + allPosts?.map(async (item) => { + if (item.price_id !== null) { + const priceData = await stripe.prices.retrieve(item.price_id); + item.price = priceData.unit_amount! / 100; + } + return item; + }), + ); + return newItems; } - } catch(e) { + } catch (e) { console.error(e); } -} \ No newline at end of file +} diff --git a/src/components/services/CategoryCarousel.tsx b/src/components/services/CategoryCarousel.tsx index 50476593..ab059765 100644 --- a/src/components/services/CategoryCarousel.tsx +++ b/src/components/services/CategoryCarousel.tsx @@ -8,18 +8,17 @@ import { getLangFromUrl, useTranslations } from "../../i18n/utils"; const lang = getLangFromUrl(new URL(window.location.href)); const values = ui[lang] as uiObject; -const productCategoryData = values.productCategoryInfo; +const productCategoryData = values.subjectCategoryInfo; import rightArrow from "../../assets/categoryIcons/circled-right-arrow.svg"; import leftArrow from "../../assets/categoryIcons/circled-left-arrow.svg"; -import garden from "../../assets/categoryIcons/garden.svg"; import history from "../../assets/categoryIcons/history.svg"; import art from "../../assets/categoryIcons/art.svg"; import geography from "../../assets/categoryIcons/geography.svg"; import math from "../../assets/categoryIcons/math.svg"; import science from "../../assets/categoryIcons/science.svg"; import specialty from "../../assets/categoryIcons/specialty.svg"; -import holiday from "../../assets/categoryIcons/history.svg"; +import holiday from "../../assets/categoryIcons/holiday.svg"; import social from "../../assets/categoryIcons/social.svg"; // import travel from "../../assets/categoryIcons/travel.svg"; // import worker from "../../assets/categoryIcons/worker.svg"; @@ -81,7 +80,7 @@ categories.map((category) => { // } }); -const categoriesData = productCategoryData.categories; +const categoriesData = productCategoryData.subjects; let allCategoryInfo: any[] = []; @@ -96,7 +95,7 @@ for (let i = 0; i < categoriesData.length; i++) { interface Props { // Define the type for the filterPosts prop - filterPosts: (currentCategory: number) => void; + filterPosts: (currentCategory: string) => void; } let dark = window.matchMedia("(prefers-color-scheme: dark)").matches; @@ -118,7 +117,7 @@ export const CategoryCarousel: Component = (props) => { id={item.id} class="flex flex-col flex-none justify-start items-center w-20 h-28 catBtn" onClick={(e) => { - props.filterPosts(item.id); + props.filterPosts(item.id.toString()); let currBtn = e.target; diff --git a/src/components/services/MobileViewCard.tsx b/src/components/services/MobileViewCard.tsx index 800dccc7..728559eb 100644 --- a/src/components/services/MobileViewCard.tsx +++ b/src/components/services/MobileViewCard.tsx @@ -16,10 +16,12 @@ const t = useTranslations(lang); interface Post { content: string; id: number; - category: string; + subject: Array; title: string; seller_name: string; major_municipality: string; + image_url: string | undefined; + seller_img: string | undefined; // minor_municipality: string; // governing_district: string; user_id: string; @@ -54,13 +56,13 @@ export const MobileViewCard: Component = (props) => { props.posts.map(async (post: any) => { post.image_urls ? (post.image_url = await downloadImage( - post.image_urls.split(",")[0] - )) + post.image_urls.split(",")[0], + )) : (post.image_url = null); // Set the default quantity to 1 post.quantity = 1; return post; - }) + }), ); setNewPosts(updatedPosts); @@ -92,15 +94,15 @@ export const MobileViewCard: Component = (props) => { } }; - function changeShowBtn(e:Event) { + function changeShowBtn(e: Event) { let postID = e?.target.id.slice(0, 1); - let showMoreID = `${ postID }more`; - let showLessID = `${ postID }less`; - let postContentID = `${ postID }content`; + let showMoreID = `${postID}more`; + let showLessID = `${postID}less`; + let postContentID = `${postID}content`; - console.log("e.target: ", e.target) + console.log("e.target: ", e.target); - console.log("id: ", postID) + console.log("id: ", postID); let showMoreDiv = document.getElementById(postID); let showMoreBtn = document.getElementById(showMoreID); @@ -110,20 +112,20 @@ export const MobileViewCard: Component = (props) => { console.log("showMoreBtn: ", showMoreBtn); console.log("showLessBtn: ", showLessBtn); - if(showMoreBtn?.classList.contains("flex")) { - showMoreBtn.classList.remove("flex"); - showMoreBtn.classList.add("hidden"); - showLessBtn?.classList.remove("hidden"); - showLessBtn?.classList.add("flex"); - postContent?.classList.add("flex"); - postContent?.classList.remove("hidden"); - } else if(showLessBtn?.classList.contains("flex")) { - showLessBtn?.classList.remove("flex"); - showLessBtn?.classList.add("hidden"); - showMoreBtn?.classList.remove("hidden"); - showMoreBtn?.classList.add("flex"); - postContent?.classList.remove("flex"); - postContent?.classList.add("hidden"); + if (showMoreBtn?.classList.contains("flex")) { + showMoreBtn.classList.remove("flex"); + showMoreBtn.classList.add("hidden"); + showLessBtn?.classList.remove("hidden"); + showLessBtn?.classList.add("flex"); + postContent?.classList.add("flex"); + postContent?.classList.remove("hidden"); + } else if (showLessBtn?.classList.contains("flex")) { + showLessBtn?.classList.remove("flex"); + showLessBtn?.classList.add("hidden"); + showMoreBtn?.classList.remove("hidden"); + showMoreBtn?.classList.add("flex"); + postContent?.classList.remove("flex"); + postContent?.classList.add("hidden"); } // if(showMoreBtn?.classList.contains("flex")) { @@ -136,175 +138,278 @@ export const MobileViewCard: Component = (props) => { return (
- { newPosts().map((post: any) => ( -
-
- { post.image_url ? ( - { - ) : ( - - - - - )} - -
-
-
-

${post.price.toFixed(2)}

- -
- - -

4.9 (30.3K)

-
-
-
- -
-
{t("formLabels.subjects")}
-

English Language Arts

-

Reading

-
- -
-
{t("formLabels.grades")}
-

PreK-1st

-
-
+ {newPosts().map((post: any) => ( +
+
+ {post.image_url ? ( + {post.image_urls.split(",")[0] + ) : ( + + + + )} + +
+
+
+

${post.price.toFixed(2)}

+ +
+ + + + + + +

4.9 (30.3K)

+
- -
-
- { post.title } -
- -
- { post.seller_img ? ( - Seller image - ) : ( - - - )} -

{post.seller_name}

-
- +
+ +
+
+ {t("formLabels.subjects")} +
+ {post.subject.map((post2: string) => { + return

{post2.subject}

; + })} +

{post.subject}

+

Reading

+
+ +
+
{t("formLabels.grades")}
+

PreK-1st

+
+
+
+ +
+
{post.title}
+ +
+ {post.seller_img ? ( + Seller image + ) : ( + + + + )} +

+ {post.seller_name} +

+
+
+ +
+ + + + + + ))}
); - -}; \ No newline at end of file +}; diff --git a/src/components/services/ServicesMain.tsx b/src/components/services/ServicesMain.tsx index 70723306..72aa929e 100644 --- a/src/components/services/ServicesMain.tsx +++ b/src/components/services/ServicesMain.tsx @@ -17,7 +17,7 @@ const t = useTranslations(lang); //get the categories from the language files so they translate with changes in the language picker const values = ui[lang] as uiObject; -const productCategories = values.productCategoryInfo.categories; +const productCategories = values.subjectCategoryInfo.subjects; const { data: user, error: userError } = await supabase.auth.getSession(); if (userError) { @@ -47,7 +47,7 @@ if (user.session === null || user.session === undefined) { interface ProviderPost { content: string; id: number; - subject: string; + subject: Array; title: string; seller_name: string; major_municipality: string; @@ -65,7 +65,7 @@ export const ServicesView: Component = () => { const [posts, setPosts] = createSignal>([]); const [searchPost, setSearchPost] = createSignal>([]); const [currentPosts, setCurrentPosts] = createSignal>([]); - const [filters, setFilters] = createSignal>([]); + const [filters, setFilters] = createSignal>([]); const [locationFilters, setLocationFilters] = createSignal>([]); const [minorLocationFilters, setMinorLocationFilters] = createSignal< Array @@ -83,9 +83,7 @@ export const ServicesView: Component = () => { let data; async function fetchPosts() { - const { data, error } = await supabase - .from("sellerposts") - .select("*"); + const { data, error } = await supabase.from("sellerposts").select("*"); if (!data) { alert("No posts available."); @@ -95,10 +93,17 @@ export const ServicesView: Component = () => { } else { const newItems = await Promise.all( data?.map(async (item) => { + item.subject = []; productCategories.forEach((productCategories) => { - if (item.product_subject.toString() === productCategories.id) { - item.subject = productCategories.name; - } + item.product_subject.map((productSubject: string) => { + if (productSubject === productCategories.id) { + item.subject.push(productCategories.name); + console.log(productCategories.name); + } + }); + // if (item.product_subject.toString() === productCategories.id) { + // item.subject = productCategories.name; + // } }); delete item.product_subject; @@ -107,9 +112,9 @@ export const ServicesView: Component = () => { item.price = priceData.unit_amount! / 100; } return item; - }) + }), ); - console.log(newItems.map(item => item.price)) + console.log(newItems.map((item) => item)); setPosts(newItems); setCurrentPosts(newItems); } @@ -133,7 +138,7 @@ export const ServicesView: Component = () => { filterPosts(); }; - const setCategoryFilter = (currentCategory: number) => { + const setCategoryFilter = (currentCategory: string) => { if (filters().includes(currentCategory)) { let currentFilters = filters().filter((el) => el !== currentCategory); setFilters(currentFilters); @@ -154,7 +159,7 @@ export const ServicesView: Component = () => { locationFilters(), minorLocationFilters(), governingLocationFilters(), - searchString() + searchString(), ); if (res === null || res === undefined) { @@ -174,17 +179,24 @@ export const ServicesView: Component = () => { setTimeout(() => { //Clear all filters after the timeout otherwise the message immediately disappears (probably not a perfect solution) clearAllFilters(); - }, 3000) + }, 3000), ); let allPosts = await allFilters.fetchAllPosts(); //Add the categories to the posts in the current language allPosts?.map((item) => { + item.subject = []; productCategories.forEach((productCategories) => { - if (item.product_subject.toString() === productCategories.id) { - item.subject = productCategories.name; - } + item.product_subject.map((productSubject: string) => { + if (productSubject === productCategories.id) { + item.subject.push(productCategories.name); + console.log(productCategories.name); + } + }); + // if (item.product_subject.toString() === productCategories.id) { + // item.subject = productCategories.name; + // } }); delete item.product_subject; }); @@ -199,10 +211,17 @@ export const ServicesView: Component = () => { timeouts = []; res.map((post) => { - productCategories.forEach((productCategory) => { - if (post.product_subject.toString() === productCategory.id) { - post.subject = productCategory.name; - } + post.subject = []; + productCategories.forEach((productCategories) => { + post.product_subject.map((productSubject: string) => { + if (productSubject === productCategories.id) { + post.subject.push(productCategories.name); + console.log(productCategories.name); + } + }); + // if (item.product_subject.toString() === productCategories.id) { + // item.subject = productCategories.name; + // } }); delete post.product_subject; }); @@ -215,7 +234,7 @@ export const ServicesView: Component = () => { const filterPostsByMajorMunicipality = (location: string) => { if (locationFilters().includes(location)) { let currentLocationFilters = locationFilters().filter( - (el) => el !== location + (el) => el !== location, ); setLocationFilters(currentLocationFilters); } else { @@ -255,7 +274,7 @@ export const ServicesView: Component = () => { let searchInput = document.getElementById("search") as HTMLInputElement; let selectedCategories = document.querySelectorAll(".selected"); const majorMuniCheckboxes = document.querySelectorAll( - "input[type='checkbox'].major-muni" + "input[type='checkbox'].major-muni", ) as NodeListOf; // const minorMuniCheckboxes = document.querySelectorAll( // "input[type='checkbox'].minor-muni" @@ -310,7 +329,7 @@ export const ServicesView: Component = () => { const clearMajorMunicipality = () => { const majorMuniCheckboxes = document.querySelectorAll( - "input[type='checkbox'].major-muni" + "input[type='checkbox'].major-muni", ) as NodeListOf; majorMuniCheckboxes.forEach((checkbox) => { @@ -406,8 +425,8 @@ export const ServicesView: Component = () => {
@@ -425,9 +444,8 @@ export const ServicesView: Component = () => {
- +
-
diff --git a/src/components/services/ViewCard.tsx b/src/components/services/ViewCard.tsx index ef414779..240d8029 100644 --- a/src/components/services/ViewCard.tsx +++ b/src/components/services/ViewCard.tsx @@ -15,14 +15,16 @@ const t = useTranslations(lang); interface Post { content: string; id: number; - subject: string; + subject: Array; title: string; seller_name: string; major_municipality: string; + seller_img: string | undefined; // minor_municipality: string; // governing_district: string; user_id: string; image_urls: string | null; + image_url: string | undefined; price: number; price_id: string; quantity: number; @@ -48,18 +50,20 @@ export const ViewCard: Component = (props) => { } createEffect(async () => { + // console.log("View Card Posts") + // console.log(props.posts) if (props.posts) { const updatedPosts = await Promise.all( - props.posts.map(async (post: any) => { + props.posts.map(async (post: Post) => { post.image_urls ? (post.image_url = await downloadImage( - post.image_urls.split(",")[0] - )) - : (post.image_url = null); + post.image_urls.split(",")[0], + )) + : (post.image_url = undefined); // Set the default quantity to 1 post.quantity = 1; return post; - }) + }), ); setNewPosts(updatedPosts); @@ -94,35 +98,41 @@ export const ViewCard: Component = (props) => { return (
-
+
{/* Left column for md+ View */}
@@ -462,7 +462,7 @@ export const ClientProfileView: Component = () => {
{ -
@@ -540,9 +538,7 @@ export const ClientProfileView: Component = () => { -
@@ -599,9 +595,7 @@ export const ClientProfileView: Component = () => { -
@@ -659,9 +653,7 @@ export const ClientProfileView: Component = () => { -
@@ -717,9 +709,7 @@ export const ClientProfileView: Component = () => { -
@@ -761,9 +751,7 @@ export const ClientProfileView: Component = () => { -
@@ -1000,9 +988,7 @@ export const ClientProfileView: Component = () => { -
{/* Left column for md+ View */} -
+
{/* Container for Mobile View */}
{/* Provider Info for Mobile View*/} -
- +
+

{t("formLabels.providerInfo")}

{/*Creates the Dropdown Arrow*/} -
-
+
+
{/* Provider Posts for Mobile View*/} -
- +
+

{t("formLabels.posts")}

{/*Creates the Dropdown Arrow*/} -
-
+
+
@@ -221,17 +218,17 @@ export const ClientProviderView: Component = (props) => { {/* Profile Information for md+ View */}