add notitication channels
This commit is contained in:
parent
cb1e41793c
commit
5da3db056d
@ -80,7 +80,7 @@
|
||||
<dialog id="installModal" class="modal overflow-hidden p-3 sm:p-0">
|
||||
<label for="installModal" class="cursor-pointer modal-backdrop"></label>
|
||||
|
||||
<div class="modal-box rounded w-full bg-primary border border-gray-600">
|
||||
<div class="modal-box rounded w-full bg-secondary border border-gray-600">
|
||||
<div class="flex flex-row items-center pt-5">
|
||||
<h4 class="text-white text-2xl font-bold text-center m-auto">
|
||||
Steps to install
|
||||
|
||||
22
src/routes/api/update-notification-channels/+server.ts
Normal file
22
src/routes/api/update-notification-channels/+server.ts
Normal file
@ -0,0 +1,22 @@
|
||||
import type { RequestHandler } from "./$types";
|
||||
|
||||
export const POST: RequestHandler = async ({ request, locals }) => {
|
||||
const data = await request.json();
|
||||
const { pb } = locals;
|
||||
let output = 'failure';
|
||||
|
||||
|
||||
try {
|
||||
await pb.collection("notificationChannels").update(data?.id, {
|
||||
'earningsSurprise': data?.earningsSurprise,
|
||||
'wiim': data?.wiim,
|
||||
})
|
||||
output = 'success';
|
||||
}
|
||||
catch(e) {
|
||||
console.log(e)
|
||||
output = 'failure';
|
||||
}
|
||||
|
||||
return new Response(JSON.stringify(output));
|
||||
};
|
||||
@ -1,10 +1,11 @@
|
||||
<script lang="ts">
|
||||
import { formatDate } from "$lib/utils";
|
||||
import ArrowLogo from "lucide-svelte/icons/move-up-right";
|
||||
import avatar from "$lib/images/visual_mod.webp";
|
||||
import HoverStockChart from "$lib/components/HoverStockChart.svelte";
|
||||
import { onMount } from "svelte";
|
||||
import { numberOfUnreadNotification } from "$lib/store";
|
||||
import SEO from "$lib/components/SEO.svelte";
|
||||
import Infobox from "$lib/components/Infobox.svelte";
|
||||
|
||||
export let data;
|
||||
export let form;
|
||||
@ -57,35 +58,10 @@
|
||||
});
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>
|
||||
{$numberOfUnreadNotification > 0 ? `(${$numberOfUnreadNotification})` : ""} Notifications
|
||||
· Stocknear</title
|
||||
>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
|
||||
<meta name="description" content="Free Stock Analysis" />
|
||||
<!-- Other meta tags -->
|
||||
<meta property="og:title" content="Notifications · Stocknear" />
|
||||
<meta property="og:description" content="Free Stock Analysis" />
|
||||
<meta
|
||||
property="og:image"
|
||||
content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"
|
||||
/>
|
||||
<meta property="og:type" content="website" />
|
||||
<!-- Add more Open Graph meta tags as needed -->
|
||||
|
||||
<!-- Twitter specific meta tags -->
|
||||
<meta name="twitter:card" content="summary_large_image" />
|
||||
<meta name="twitter:title" content="Notifications · Stocknear" />
|
||||
<meta name="twitter:description" content="Free Stock Analysis" />
|
||||
<meta
|
||||
name="twitter:image"
|
||||
content="https://stocknear-pocketbase.s3.amazonaws.com/logo/meta_logo.jpg"
|
||||
/>
|
||||
<!-- Add more Twitter meta tags as needed -->
|
||||
</svelte:head>
|
||||
<SEO
|
||||
title="Stock Market Notifications | Real-Time Updates & Alerts"
|
||||
description="Stay informed with real-time stock market notifications. Get instant alerts on price changes, trends, and market movements to make smarter investment decisions."
|
||||
/>
|
||||
|
||||
<section
|
||||
class="w-full max-w-3xl sm:max-w-[1400px] overflow-hidden min-h-screen pb-20 pt-5 px-4 lg:px-3"
|
||||
@ -102,20 +78,26 @@
|
||||
<div
|
||||
class="relative flex justify-center items-start overflow-hidden w-full"
|
||||
>
|
||||
<main class="w-full lg:w-3/4 lg:pr-5">
|
||||
<div class="mb-6 border-b-[2px]">
|
||||
<main class="w-full lg:w-3/4 lg:pr-10">
|
||||
<div class="mb-3 border-b-[2px]">
|
||||
<h1 class="mb-1 text-white text-2xl sm:text-3xl font-bold">
|
||||
Notification
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
<div class="mb-4">
|
||||
<Infobox
|
||||
text="Personalize your notifications on your account page."
|
||||
/>
|
||||
</div>
|
||||
|
||||
{#if notificationList?.length !== 0}
|
||||
<div class="flex flex-col items-start w-full text-white">
|
||||
{#each notificationList as item}
|
||||
{#if item?.notifyType === "priceAlert"}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="sm:hover:bg-[#2B2B2B] pb-3 sm:p-3 mb-6 sm:mb-3 text-gray-200 w-full {!item?.readed
|
||||
class=" pb-3 sm:p-3 mb-6 sm:mb-3 text-white w-full {!item?.readed
|
||||
? 'bg-[#F9AB00] bg-opacity-[0.1]'
|
||||
: ''} "
|
||||
>
|
||||
@ -163,7 +145,7 @@
|
||||
{:else if item?.notifyType === "wiim"}
|
||||
<!-- svelte-ignore a11y-click-events-have-key-events -->
|
||||
<div
|
||||
class="sm:hover:bg-[#2B2B2B] pb-3 sm:p-3 mb-6 sm:mb-3 text-gray-200 w-full {!item?.readed
|
||||
class=" pb-3 sm:p-3 mb-6 sm:mb-3 text-white w-full {!item?.readed
|
||||
? 'bg-[#F9AB00] bg-opacity-[0.1]'
|
||||
: ''} "
|
||||
>
|
||||
@ -207,7 +189,7 @@
|
||||
</div>
|
||||
{:else if item?.notifyType === "earningsSurprise"}
|
||||
<div
|
||||
class="sm:hover:bg-[#2B2B2B] pb-3 sm:p-3 mb-6 sm:mb-3 text-gray-200 w-full {!item?.readed
|
||||
class=" pb-3 sm:p-3 mb-6 sm:mb-3 text-white w-full {!item?.readed
|
||||
? 'bg-[#F9AB00] bg-opacity-[0.1]'
|
||||
: ''} "
|
||||
>
|
||||
|
||||
@ -47,18 +47,7 @@ export const GET = async ({ locals, url, cookies }) => {
|
||||
.authWithOAuth2Code(provider.name, code, expectedVerifier, redirectURL);
|
||||
|
||||
|
||||
//oauthUsername = generateUsername(newUser['meta']['name'].split(' ').join('')).toLowerCase();
|
||||
|
||||
// Check if user was created or existed already
|
||||
/*
|
||||
if(newUser?.meta?.isNew === true) {
|
||||
await locals.pb?.collection('users').update(
|
||||
newUser['record']['id'], {
|
||||
'freeTrial' : true,
|
||||
'tier': 'Pro', //Give new users a free trial for the Pro Subscription
|
||||
});
|
||||
}
|
||||
*/
|
||||
|
||||
} catch (err) {
|
||||
console.log("Error logging in with OAuth2 user", err);
|
||||
redirect(302, "/register");
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
<script lang="ts">
|
||||
import { numberOfUnreadNotification } from "$lib/store";
|
||||
import { openLemonSqueezyUrl } from "$lib/lemonsqueezy";
|
||||
//import Discount from '$lib/components/Discount.svelte';
|
||||
import { onMount } from "svelte";
|
||||
|
||||
@ -6,6 +6,45 @@ export const load = async ({ locals }) => {
|
||||
redirect(303, "/login");
|
||||
}
|
||||
|
||||
const getNotificationChannels = async () => {
|
||||
const userId = user?.id;
|
||||
let output = {};
|
||||
|
||||
try {
|
||||
// Check if the user already exists in the collection
|
||||
output = await pb.collection("notificationChannels").getFirstListItem(`user="${userId}"`);
|
||||
} catch (error) {
|
||||
if (error.status === 404) {
|
||||
try {
|
||||
// Fetch the collection schema to dynamically get all boolean fields
|
||||
const collectionSchema = await pb.collection("notificationChannels").getFullList();
|
||||
|
||||
// Find all boolean fields and set them to `true`
|
||||
const defaultValues = collectionSchema[0]
|
||||
? Object.keys(collectionSchema[0]).reduce((acc, key) => {
|
||||
if (typeof collectionSchema[0][key] === "boolean") {
|
||||
acc[key] = true;
|
||||
}
|
||||
return acc;
|
||||
}, {})
|
||||
: {};
|
||||
|
||||
// Ensure the user field is included
|
||||
defaultValues.user = userId;
|
||||
|
||||
// Create the new record
|
||||
output = await pb.collection("notificationChannels").create(defaultValues);
|
||||
} catch (creationError) {
|
||||
console.error("Error creating new user notification channel:", creationError);
|
||||
}
|
||||
} else {
|
||||
console.error("Error checking for existing user:", error);
|
||||
}
|
||||
}
|
||||
return output; // Return only the latest item
|
||||
};
|
||||
|
||||
|
||||
const getPushSubscriptionData = async () => {
|
||||
let output = {};
|
||||
try {
|
||||
@ -28,8 +67,6 @@ const getPushSubscriptionData = async () => {
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
const getSubscriptionData = async () => {
|
||||
const output =
|
||||
(
|
||||
@ -45,9 +82,12 @@ const getPushSubscriptionData = async () => {
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
return {
|
||||
getSubscriptionData: await getSubscriptionData(),
|
||||
getPushSubscriptionData: await getPushSubscriptionData(),
|
||||
getNotificationChannels: await getNotificationChannels(),
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
@ -19,6 +19,14 @@
|
||||
|
||||
let nottifPermGranted: boolean | null = null;
|
||||
let isPushSubscribed = data?.getPushSubscriptionData !== null ? true : false;
|
||||
let notificationChannels = data?.getNotificationChannels;
|
||||
|
||||
const mode = Object?.entries(notificationChannels)
|
||||
.filter(([key, value]) => typeof value === "boolean") // Filter boolean properties
|
||||
.reduce((acc, [key, value]) => {
|
||||
acc[key] = value; // Add to mode object
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
let subscriptionData = data?.getSubscriptionData;
|
||||
let isClicked = false;
|
||||
@ -199,6 +207,26 @@
|
||||
}
|
||||
loading = false;
|
||||
}
|
||||
|
||||
async function updateNotificationChannels() {
|
||||
const postData = {
|
||||
id: notificationChannels?.id,
|
||||
...mode,
|
||||
};
|
||||
|
||||
const response = await fetch("/api/update-notification-channels", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(postData),
|
||||
});
|
||||
}
|
||||
|
||||
async function toggleMode(state) {
|
||||
mode[state] = !mode[state];
|
||||
await updateNotificationChannels();
|
||||
}
|
||||
</script>
|
||||
|
||||
<SEO
|
||||
@ -251,13 +279,51 @@
|
||||
>
|
||||
</div>
|
||||
|
||||
{#if pwaInstalled}
|
||||
<div
|
||||
class="mt-6 rounded border border-gray-600 p-4 text-base xs:p-4 xs:text-lg text-white"
|
||||
>
|
||||
<h2 class="text-white text-2xl font-semibold mb-3">
|
||||
Push Notification
|
||||
</h2>
|
||||
<div
|
||||
class="mt-6 rounded border border-gray-600 p-4 text-base xs:p-4 xs:text-lg text-white"
|
||||
>
|
||||
<h2 class="text-white text-2xl font-semibold mb-3">Notification</h2>
|
||||
Customize your notification alerts based on your preferences.
|
||||
|
||||
<div class="flex flex-col items-start w-full mt-4 mb-4">
|
||||
<div class="flex w-full md:w-1/3 justify-between items-center">
|
||||
<span class="text-white">Earnings Surprise</span>
|
||||
<label class="inline-flex cursor-pointer relative">
|
||||
<input
|
||||
on:click={() => toggleMode("earningsSurprise")}
|
||||
type="checkbox"
|
||||
checked={mode["earningsSurprise"]}
|
||||
value={mode["earningsSurprise"]}
|
||||
class="sr-only peer"
|
||||
/>
|
||||
<div
|
||||
class="w-10 h-5 bg-gray-600 rounded-full peer-checked:after:translate-x-4 peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[0.25rem] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-purple-500"
|
||||
></div>
|
||||
</label>
|
||||
</div>
|
||||
<div
|
||||
class=" mt-2 flex w-full md:w-1/3 justify-between items-center"
|
||||
>
|
||||
<span class="text-white"> Why Priced Moved </span>
|
||||
<label class="inline-flex cursor-pointer relative">
|
||||
<input
|
||||
on:click={() => toggleMode("wiim")}
|
||||
type="checkbox"
|
||||
checked={mode["wiim"]}
|
||||
value={mode["wiim"]}
|
||||
class="sr-only peer"
|
||||
/>
|
||||
<div
|
||||
class="w-10 h-5 bg-gray-600 rounded-full peer-checked:after:translate-x-4 peer-checked:after:border-white after:content-[''] after:absolute after:top-0.5 after:left-[0.25rem] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-4 after:w-4 after:transition-all peer-checked:bg-purple-500"
|
||||
></div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3 class="text-white text-xl font-semibold mb-2 mt-4">
|
||||
Push Notification
|
||||
</h3>
|
||||
{#if pwaInstalled}
|
||||
<div class="mt-3">
|
||||
{#if nottifPermGranted === null}
|
||||
<p>Checking permissions...</p>
|
||||
@ -302,8 +368,21 @@
|
||||
</p>
|
||||
{/if}
|
||||
</div>
|
||||
</div>
|
||||
{/if}
|
||||
{:else}
|
||||
<div class="mt-2">
|
||||
<p class="mb-3">
|
||||
You can activate the push notification only if you downloaded
|
||||
the app.
|
||||
</p>
|
||||
<label
|
||||
for="installModal"
|
||||
class="flex-none rounded px-4 py-1.5 text-sm font-semibold text-black cursor-pointer bg-[#fff] focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-900"
|
||||
>
|
||||
Install the App
|
||||
</label>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="mt-6 rounded border border-gray-600 p-4 text-base xs:p-4 xs:text-lg text-white"
|
||||
@ -670,3 +749,55 @@
|
||||
</div>
|
||||
</dialog>
|
||||
<!-- End Cancel Subscription Modal -->
|
||||
|
||||
<!--Start Create Watchlist Modal-->
|
||||
<input type="checkbox" id="installModal" class="modal-toggle" />
|
||||
|
||||
<dialog id="installModal" class="modal overflow-hidden p-3 sm:p-0">
|
||||
<label for="installModal" class="cursor-pointer modal-backdrop"></label>
|
||||
|
||||
<div class="modal-box rounded w-full bg-secondary border border-gray-600">
|
||||
<div class="flex flex-row items-center pt-5">
|
||||
<h4 class="text-white text-2xl font-bold text-center m-auto">
|
||||
Steps to install
|
||||
</h4>
|
||||
<label
|
||||
for="installModal"
|
||||
class="inline-block cursor-pointer absolute right-3 top-3 text-[1.3rem] sm:text-[1.8rem] text-white"
|
||||
>
|
||||
<svg
|
||||
class="w-6 h-6 sm:w-8 sm:h-8"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
><path
|
||||
fill="white"
|
||||
d="m6.4 18.308l-.708-.708l5.6-5.6l-5.6-5.6l.708-.708l5.6 5.6l5.6-5.6l.708.708l-5.6 5.6l5.6 5.6l-.708.708l-5.6-5.6z"
|
||||
/></svg
|
||||
>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="text-white flex flex-col justify-center items-center text-xl h-full"
|
||||
>
|
||||
<ul class="list-decimal list-inside text-left mt-5">
|
||||
<li class="mb-2">Tap on the Safari share button.</li>
|
||||
<li class="mb-2">Tap on "Add to Home Screen."</li>
|
||||
<li class="mb-4">Tap on "Add."</li>
|
||||
|
||||
<p class="text-lg mb-4">
|
||||
Note that web apps on iOS can only be installed using Safari.
|
||||
</p>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="border-t border-gray-600 mt-2">
|
||||
<label
|
||||
for="installModal"
|
||||
class="mt-4 font-semibold text-white text-xl m-auto flex justify-center"
|
||||
>
|
||||
Close
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</dialog>
|
||||
|
||||
@ -35,14 +35,7 @@ export const actions = {
|
||||
//let username = generateUsername(formData.name.split(' ').join('')).toLowerCase();
|
||||
|
||||
try {
|
||||
await locals.pb.collection("users").create(formData);
|
||||
/*
|
||||
await locals.pb?.collection('users').update(
|
||||
newUser?.id, {
|
||||
'freeTrial' : true,
|
||||
'tier': 'Pro', //Give new users a free trial for the Pro Subscription
|
||||
});
|
||||
*/
|
||||
const newUser = await locals.pb.collection("users").create(formData);
|
||||
|
||||
await locals.pb.collection("users").requestVerification(formData.email);
|
||||
} catch (err) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user