Snippets Collections
type Props = {
  state: 'success' | 'partial' | 'failure'
}

const props = defineProps<Props>()

const states: Record<Props['state'], { icon: IconDefinition; color: Color }> = {
  success: { icon: faCheckCircle, color: 'success' },
  partial: { icon: faCircleMinus, color: 'warning' },
  failure: { icon: faCircleXmark, color: 'error' },
}

const icon = computed(() => states[props.state].icon)
const color = computed(() => states[props.state].color)
var
val;
val = 12;
console.log("数字为 " + val);
val = "CodeWhy";
console.log("字符串为 " + val);

<script setup lang="ts">
import { ref } from "vue";

type CarouselElement = {
  link: string;
  image: string;
  label: string;
  countryCode?: string;
};

interface Props {
  carouselElements: CarouselElement[];
}

const props = withDefaults(defineProps<Props>(), {
  carouselElements: () => [
    {
      link: "/",
      image: "/assets/images/100.webp",
      label: "Phenom 100",
    },
    {
      link: "/",
      image: "/assets/images/100.webp",
      label: "Phenom 100",
    },
    {
      link: "/",
      image: "/assets/images/100.webp",
      label: "Phenom 100",
    },
  ],
});
const leftArrowRef = ref<HTMLButtonElement | null>(null);
const rightArrowRef = ref<HTMLButtonElement | null>(null);
const showArrows = ref(false);
const scrollableContainerRef = ref<HTMLDivElement | null>(null);

const scroll = (direction: "left" | "right") => {
  if (scrollableContainerRef.value) {
    const scrollAmount = 300;

    if (direction === "left") {
      scrollableContainerRef.value.scrollTo({
        left: scrollableContainerRef.value.scrollLeft - scrollAmount,
        behavior: "smooth",
      });
    } else {
      scrollableContainerRef.value.scrollTo({
        left: scrollableContainerRef.value.scrollLeft + scrollAmount,
        behavior: "smooth",
      });
    }
  }
};
</script>
interface User{
    fname: string,
    lname: string,
    mobNumb: number
}
function sendUserDetails<T>(userInput: T[] ): T {
    return userInput[0];
}
const userOne = sendUserDetails<User>([{fname:"Donald",lname:"Trumph",mobNumb:7895474474}]);
console.log(userOne.fname);
console.log(userOne.lname);
console.log(userOne.mobNumb);
function identity<T>(arg: T): T {
    return arg;
}

let output1 = identity<string>("myString");
let output2 = identity<number>(100);
function getFirstElement<T>(arr: T[]) {
    return arr[0];
}

const el = getFirstElement(["neil", "nithin","mukesh"]);
console.log(el.toUpperCase())
function identity<T>(value: T): T {
    return value;
}

// Using the generic function
let result = identity<number>(5); // here, T is replaced with number
console.log(result); // Output: 5

let value = identity<string>("Hello"); // here, T is replaced with string
console.log(value.toUpperCase());
function ReturnType<T>(val: T ): T {
    return val;
}

const elementstring = ReturnType("hello");
console.log(elementstring.toUpperCase())
console.log(typeof(elementstring))

const elementNumber = ReturnType(1254);
console.log(typeof(elementNumber))
function getFirstElement(arr: (string | number)[]) {
    return arr[0];
}
const firstEle = getFirstElement(["neil", "nithin", "mukesh"]);
firstEle.toUpperCase()
function getFirstElement(arr: (string | number)[]) {
    return arr[0];
}
const firstEle = getFirstElement(["neil", "nithin", "mukesh"]);
console.log(firstEle);
const merlin = new Merlin({ apiKey:"<YOUR_OPENAI_KEY>", merlinConfig: {apiKey: "<YOUR_MERLIN_API_KEY>"} });`
import { Merlin } from "merlin-node";

const apiKey = "<YOUR_MERLIN_API_KEY>"; // Replace with your API key from Merlin
const merlin = new Merlin({ merlinConfig: { apiKey } });

async function createCompletion() {
  try {
    const completion = await merlin.chat.completions.create({
      messages: [
        { role: "system", content: "You are a helpful assistant." },
        {
          role: "user",
          content: [
            {
              type: "image_url",
              image_url:
                "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg",
            },
            {
              type: "text",
              text: "What’s in this image?",
            },
          ],
        },
      ],
      model: "gemini-pro-vision",
    });

    console.log(completion.choices[0].message.content);
  } catch (error) {
    console.error("Error creating completion:", error);
  }
}

createCompletion();
type SantasFavoriteCookies = 'ginger-bread' | 'chocolate-chip';
import { createContext, useReducer, ReactNode } from 'react';

type State = {
  user: any | null;
};

const initialState: State = {
  user: null,
};

enum ActionType {
  SET_USER = 'SET_USER',
}

export const reducer = (
  state: State,
  action: {
    type: keyof typeof ActionType;
    payload: any;
  },
) => {
  switch (action.type) {
    case ActionType.SET_USER:
      return {
        ...state,
        user: action.payload,
      };
    default:
      return state;
  }
};

type GlobalContextType = {
  user: State['user'];
  setUser: (newUser: State['user']) => void;
};

export const GlobalContext = createContext<GlobalContextType>(
  {} as GlobalContextType,
);

const GlobalProvider = ({ children }: { children: ReactNode }) => {
  const [state, dispatch] = useReducer(reducer, initialState);

  const contextValue: GlobalContextType = {
    ...state,

    //* mutations
    setUser: (newUser: State['user']) => {
      dispatch({ type: ActionType.SET_USER, payload: newUser });
    },
  };

  return (
    <GlobalContext.Provider value={contextValue}>
      {children}
    </GlobalContext.Provider>
  );
};

export default GlobalProvider;
import React fron "react";

type ButtonOrLinkProps = | (React.ButtonHTMLAttributes<HTMLButtonElement> & { as?: "Button"}) | (React.AnchorHTMLAttrributes<HTMLAnchorElement>) & { as: "a"});

const ButtonOrLink = (props: ButtonOrLinkProps) => {
  if(props.as === "a"){
    return <a {...props} />
  }
  return <button {...props} />
}

/** Use case */
<ButtonOrLink  onClick={(e) => {console.log(e)}}/>
<ButtonOrLink as="a"  onClick={(e) => {console.log(e)}}/>
  
type ParseProjects = (arg: {
						  file: File;
					}) => Props['data'][number]['data'][number]['data'][number][];

const parseProjectsDefaultValue: ReturnType<ParseProjects> = [];

export const parseProjects: ParseProjects = ({ file }) => {

	try {
		// ! Projects make project array
		return Object.entries(file.project).reduce((acc, item) => {
			const currentKey = item[0] as PROJECT;
			if (item[1]) {
				const result: ReturnType<ParseProjects>[number] = {
				project: currentKey,
				status: CUSTOMER_STATUS.CONTACTED, 
				label: '',
			};
			
			return [...acc, result];
			
			}
			
		return acc;
			
		}, parseProjectsDefaultValue);
	
	} catch {

	return parseProjectsDefaultValue;

	}

};
type GroupeDataByDate = (arg: { filteredFiles: CustomerFile[] }) => {
	[key: string]: CustomerStatusCardsProps['data'][number]['data'][number][];
};

const groupeDataByDateDefaultValue: ReturnType<GroupeDataByDate> = {};

export const groupeDataByDate: GroupeDataByDate = ({ filteredFiles }) => {
	try {
	// ! Group files by date
	return filteredFiles.reduce((acc, item) => {
		const computedProjects = parseProjects({ file: item });
		const filesByDate = { title: item.customer, data: computedProjects };
		
		if (acc[item.updatedAt]) {
			return { ...acc, [item.updatedAt]: [...acc[item.updatedAt], filesByDate] };
		}
		
		return { ...acc, [item.updatedAt]: [filesByDate] };
		
		}, groupeDataByDateDefaultValue);
	} catch (error) {
	return groupeDataByDateDefaultValue;
	}
};
Array.findIndex((item) => item === indextoFind) return index
import { isArray as isArrayUtils, isObject as isObjectUtils } from '@utils/functions';

import { compareString } from '../compareString';

// ****************************
// ? move to @utils/functions
type MyObject = { [key: string]: unknown };
type IsObject = (data: unknown) => data is MyObject;
export const isObject: IsObject = (data): data is MyObject => isObjectUtils(data);

type Array = unknown[];
type IsArray = (data: unknown) => data is Array;
export const isArray: IsArray = (data): data is Array => isArrayUtils(data);
// ****************************

export type FilterFileByValue = (file: unknown, value: string) => boolean;

export const filterFileByValue: FilterFileByValue = (file, value) => {
	try {
		const fileValues = (isObject(file) && Object.values(file)) || [];
		
		const filteredFileValues = fileValues.filter((fileValue) => {
			if (typeof fileValue === 'string') {
				return compareString({ string1: fileValue, string2: value });
			}

			if (isArray(fileValue)) {
				const values = fileValue.filter((nestedFile) => filterFileByValue(nestedFile, value));
				return !!values.length;
			
			}
		
		return filterFileByValue(fileValue, value);
		
		});
		return !!filteredFileValues.length;
		
	} catch {
		return false;
	}

};
import {
	ERepaymentReason,
	ESaleStatus,
	ESaleType,
	ESaleVersion,
} from "@lendtable/common/dtos/SaleDto";
import { TTransaction, withTransaction } from "../utils/mysql";

import {
	calculatePayPeriodBalanceEspp,
	calculatePayPeriodBalanceK401,
} from "@lendtable/common/config/dynamic-payouts";
import { isPaidOut } from "@lendtable/common/config/sale";
import { EBalanceContributionStatus } from "@lendtable/common/dtos/BalanceContributionDto";
import { EBalanceSnapshotType } from "@lendtable/common/dtos/BalanceSnapshotDto";
import { EPayoutTransactionStatus } from "@lendtable/common/dtos/PayoutDto";
import { EPlaidConnectionType } from "@lendtable/common/dtos/PlaidConnectionDto";
import { EStatusUpdateType } from "@lendtable/common/dtos/StatusUpdateDto";
import { PayPeriodStatus } from "@prisma/client";
import { Customer } from "../entities/Customer";
import { prisma } from "../prisma/prisma";
import BalanceContributionRepository from "../repositories/BalanceContributionRepository";
import BalanceSnapshotRepository from "../repositories/BalanceSnapshotRepository";
import CustomerRepository from "../repositories/CustomerRepository";
import PayoutRepository from "../repositories/PayoutRepository";
import PlaidConnectionRepository from "../repositories/PlaidConnectionRepository";
import SaleRepository from "../repositories/SaleRepository";
import HotShot from "../utils/hot-shot";
import { logger } from "../utils/logger";
import { REPAYMENTS_PRODUCT_ID, REPAYMENT_PLAN } from "../utils/stripe";
import { isClonedCustomer } from "../utils/user";
import PlaidService from "./PlaidService";
import SaleStatusService from "./SaleStatusService";
import SlackService from "./SlackService";
import StripeService from "./StripeService";

class BalancesService {
	// Recalculates the customer's lendtable balance
	public static async updateLendtableBalance(
		customer: Customer,
		t?: TTransaction
	) {
		// Lendtable balance goes UP as customers get payouts, multiplied by the interest rate for each sale
		// Lendtable balance goes DOWN when the customer pays us back, or gets credit for special actions, i.e. we subtract the total (confirmed) balance contributions, in the order which they were confirmed (updated)

		// Combine the customer's sales and payouts, only choosing sales for which the contract is accepted and payouts that have not failed
		const sales = await SaleRepository.getAllByCustomerId(
			customer.id,
			"ASC",
			undefined,
			t
		);
		const payouts = await PayoutRepository.getAllByCustomerId(
			customer.id,
			"ASC",
			undefined,
			t
		);
		const payoutNonDynamic = payouts.filter((p) => {
			return p.payPeriodId === null;
		});
		const payoutsNotFailed = payoutNonDynamic.filter((p) => {
			return (
				p.payoutTransactionStatus === EPayoutTransactionStatus.Pending ||
				p.payoutTransactionStatus === EPayoutTransactionStatus.Successful
			);
		});
		const payPeriods = await prisma.payPeriod.findMany({
			// OK that this isn't in the same transaction,
			// because we never create payPeriods in this transaction
			// payPeriods are only created in Prisma
			where: {
				customerId: customer.id,
				status: PayPeriodStatus.APPROVED,
			},
			orderBy: {
				payDateProjected: "desc",
			},
		});
		const salesWithPayoutsAndPayPeriods = sales.map((sale) => ({
			sale,
			payouts: payoutsNotFailed.filter((p) => p.saleId === sale.id),
			payPeriods: payPeriods.filter((pp) => {
				return pp.esppSaleId === sale.id || pp.k401SaleId === sale.id;
			}),
			balanceContributions: [],
		}));

		// Go over the combined sales and sum the payouts
		const salesWithPayoutsSum = salesWithPayoutsAndPayPeriods.map((sp) => ({
			...sp,
			payoutsSumCents: sp.payouts.reduce(
				(acc, p) => acc + p.amountCents + p.subscriptionFromPayoutCents,
				0
			),
			dynamicPayoutsSumCents: sp.payPeriods.reduce((acc, pp) => {
				if (sp.sale.saleType === ESaleType.K401) {
					return acc + (pp.k401PayoutAmount ?? 0);
				} else if (sp.sale.saleType === ESaleType.Espp) {
					return acc + (pp.esppPayoutAmount ?? 0);
				} else {
					throw new Error(`Invalid saleType ${sp.sale.id}`);
				}
			}, 0),
		}));

		// Apply the interest rate to the sum of the payouts
		const salesWithPayoutsSumInterest = salesWithPayoutsSum.map((sp) => ({
			...sp,
			payoutsSumWithInterestCents: Math.floor(
				sp.payoutsSumCents * (sp.sale.interestRatio() ?? 1)
			),
			payPeriodSumWithOurShareCents: sp.payPeriods.reduce((acc, pp) => {
				const payoutSumForPeriod = payouts
					.filter((p) => {
						// conditional is different than above because we include scheduled payouts
						return (
							p.payPeriodId === pp.id &&
							p.payoutTransactionStatus !== EPayoutTransactionStatus.Failed
						);
					})
					.reduce((acc, p) => acc + p.amountCents, 0);
				if (payoutSumForPeriod === 0) {
					// If all payouts for this payPeriod have failed, then the payPeriod will not count towards balance
					return acc;
				}
				const shouldBePaidAmount =
					(pp.esppPayoutAmount ?? 0) +
					(pp.k401PayoutAmount ?? 0) -
					(pp.subscriptionFee ?? 0);
				if (payoutSumForPeriod !== shouldBePaidAmount) {
					// Edge case where the payPeriod has multiple payouts, and there is both succesful and failed payouts and we have not resent the failed payouts
					// We need to manually reduce the values on the payPeriod
					if (!isClonedCustomer(customer)) {
						void SlackService.postMessage({
							text:
								`Pay Period ${pp.payDateProjectedStr} for customer ${customer.id} has multiple payouts, and there are both succesful and failed payouts.\n` +
								`The sum of payouts sent doesn't not match payoutAmounts stored on the payPeriod. We need to manually adjust.\n` +
								`Should be paid: $${shouldBePaidAmount / 100}, actual paid: $${
									payoutSumForPeriod / 100
								}.`,
							channel: SlackService.DYNAMIC_CHANNEL,
						});
					}
				}

				if (sp.sale.saleType === ESaleType.K401) {
					// Use pp.k401OurShare once backfilled
					const taxRate = sp.payPeriods[0].taxRate; // use the taxRate from the most recent approved payPeriod
					return (
						acc +
						calculatePayPeriodBalanceK401({ payPeriod: pp, taxRate }).balance
					);
				}
				if (sp.sale.saleType === ESaleType.Espp) {
					// Use pp.esppOurShare once backfilled
					return acc + calculatePayPeriodBalanceEspp(pp).balance;
				}
				throw new Error("Invalid saleType");
			}, 0),
		}));

		// Mark the payouts as being completed when enough money is sent to cover the loan amount, with a leeway of 10 USD
		for (const { sale, payoutsSumCents } of salesWithPayoutsSumInterest) {
			if (
				sale.saleStatus !== ESaleStatus.PayoutScheduled &&
				sale.saleStatus !== ESaleStatus.PayoutPaused
			) {
				continue;
			}
			// Only legacy sales can move to PayoutComplete in this way
			if (
				sale.saleVersion !== ESaleVersion._20220428 &&
				sale.saleVersion !== ESaleVersion._20220505
			) {
				continue;
			}
			if (
				payoutsSumCents > 0 &&
				payoutsSumCents >= (sale.loanCents() ?? 0) - 10 * 100
			) {
				// Update SaleStatus
				const oldStatus = sale.saleStatus;
				sale.saleStatus = ESaleStatus.PayoutComplete;
				await SaleRepository.updateSaleStatus(sale.id, sale.saleStatus, t);
				await SaleStatusService.onStatusChanged(
					sale,
					customer,
					{
						oldStatus,
						statusUpdateType: EStatusUpdateType.PayoutsCompleted,
						recursionDepth: 0,
					},
					t
				);
				sale.repaymentReason = ERepaymentReason.ContractTermEnded;
				await SaleRepository.updateRepaymentReason(
					sale.id,
					sale.repaymentReason,
					t
				);
			}
		}

		// To start off, make the balances equal to the payouts sum with interest
		const salesWithBalances = salesWithPayoutsSumInterest.map((sp) => ({
			...sp,
			balanceCents:
				sp.payoutsSumWithInterestCents + sp.payPeriodSumWithOurShareCents,
		}));

		// Apply balance contributions, draining the balances
		const balanceContributions =
			await BalanceContributionRepository.getAllByCustomerIdStatusOrderUpdated(
				customer.id,
				EBalanceContributionStatus.Confirmed,
				"ASC",
				undefined,
				t
			);
		// Apply BalanceContributions that have a SaleId first
		// Refunds and disputes all have saleId set
		for (const balanceContribution of balanceContributions.filter(
			(b) => b.saleId !== null
		)) {
			const sb = salesWithBalances.find(
				(s) => s.sale.id === balanceContribution.saleId
			);
			// TODO how should we handle the case where the sale is missing?
			if (!sb) {
				continue;
			}
			sb.balanceCents -= balanceContribution.amountCents;
		}
		// Apply BalanceContributions without a SaleId second
		for (const balanceContribution of balanceContributions.filter(
			(b) => b.saleId === null
		)) {
			const sb = salesWithBalances.find((sb) => sb.balanceCents > 0);
			if (!sb) {
				continue;
			}
			sb.balanceCents -= balanceContribution.amountCents;
			// Update the BalanceContribution's SaleId
			balanceContribution.saleId = sb.sale.id;
			await BalanceContributionRepository.updateSaleId(
				balanceContribution.id,
				balanceContribution.saleId,
				t
			);
		}

		// Sum the total lendtable balance
		const lendtableBalanceCents = salesWithBalances.reduce(
			(acc, sb) => acc + sb.balanceCents,
			0
		);
		// Sum total 401(k) and ESPP balances
		const lendtableBalanceK401Cents = salesWithBalances
			.filter((sb) => sb.sale.saleType === ESaleType.K401)
			.reduce((acc, sb) => acc + sb.balanceCents, 0);
		const lendtableBalanceEsppCents = salesWithBalances
			.filter((sb) => sb.sale.saleType === ESaleType.Espp)
			.reduce((acc, sb) => acc + sb.balanceCents, 0);

		// Save overall Customer balances
		customer.lendtableBalanceCents = lendtableBalanceCents;
		customer.lendtableBalanceK401Cents = lendtableBalanceK401Cents;
		customer.lendtableBalanceEsppCents = lendtableBalanceEsppCents;
		await CustomerRepository.updateLendtableBalances(
			customer.id,
			{
				lendtableBalanceCents,
				lendtableBalanceK401Cents,
				lendtableBalanceEsppCents,
			},
			t
		);

		// Save individual Sale balances
		for (const {
			sale,
			balanceCents,
			payoutsSumCents,
			dynamicPayoutsSumCents,
		} of salesWithBalances) {
			sale.balanceCents = balanceCents;
			sale.payoutSumCents = payoutsSumCents + dynamicPayoutsSumCents;
		}
		await Promise.all([
			...salesWithBalances.map((sb) =>
				SaleRepository.updateBalanceCents(sb.sale.id, sb.sale.balanceCents, t)
			),
			...salesWithBalances.map((sb) =>
				SaleRepository.updatePayoutSumCents(
					sb.sale.id,
					sb.sale.payoutSumCents,
					t
				)
			),
		]);

		// Sales that have had been paid out and were drained to a balance of zero are changed to RepaymentComplete
		const salesToComplete = salesWithBalances.filter(
			(sb) => isPaidOut(sb.sale) && sb.balanceCents <= 10
		);
		for (const { sale } of salesToComplete) {
			if (sale.saleStatus === ESaleStatus.RepaymentComplete) {
				continue;
			}

			const customerRepaymentPlans =
				await StripeService.getCustomerRepaymentSubscriptions(customer);

			if (customerRepaymentPlans) {
				const saleRepaymentPlan = customerRepaymentPlans?.find(
					(rp) => rp.saleId === sale.id
				);
				if (saleRepaymentPlan && saleRepaymentPlan.planStatus !== "canceled") {
					await StripeService.cancelSubscription({
						subscriptionId: saleRepaymentPlan.id,
						stripeSubscriptionProductId: REPAYMENTS_PRODUCT_ID,
						stripeSubscriptionTypeMedata: REPAYMENT_PLAN,
						stripeSubscriptionSaleIdMetadata: sale.id,
					});
				}
			}

			// Update SaleStatus
			const oldStatus = sale.saleStatus;
			sale.saleStatus = ESaleStatus.RepaymentComplete;
			await SaleRepository.updateSaleStatus(sale.id, sale.saleStatus, t);
			await SaleStatusService.onStatusChanged(
				sale,
				customer,
				{
					oldStatus,
					statusUpdateType: EStatusUpdateType.Repaid,
					recursionDepth: 0,
				},
				t
			);
		}

		// Remove preapproved status from sales with repaid parents.
		if (salesToComplete) {
			await this.removePreapprovedFromEsppSaleIfParentAndSiblingsRepaid(
				customer.id,
				t
			);
		}
	}

	// Remove preapproved status from child sales if parent sale and sibling sales have been repaid
	// Call after some sales are repaid
	public static async removePreapprovedFromEsppSaleIfParentAndSiblingsRepaid(
		customerId: string,
		t?: TTransaction
	) {
		const sales = await SaleRepository.getAllByCustomerId(
			customerId,
			undefined,
			undefined,
			t
		);
		const preapprovedSales = sales.filter(
			(sale) => sale.saleType === ESaleType.Espp && sale.preapproved
		);

		for (const childSale of preapprovedSales) {
			// check the parent sale and sibling sales
			if (!childSale.parentId) {
				continue;
			}
			const targetSales = await SaleRepository.getAllByParentId(
				childSale.parentId,
				undefined,
				undefined,
				t
			);
			const allRepaid = targetSales.every((sale) => {
				return (
					sale.preapproved || sale.saleStatus === ESaleStatus.RepaymentComplete
				);
			});
			if (allRepaid) {
				await SaleRepository.updatePreapproved(childSale.id, false, t);
			}
		}
	}

	// Recalculates the customer's 401(k) balance
	public static async updateK401Balance(customer: Customer, t?: TTransaction) {
		// The 401(k) balance is equal to what's in the customer's 401(k) account(s), we use Plaid to get that info
		const balance = await PlaidService.getCustomerBalance(
			customer,
			EPlaidConnectionType.K401,
			t
		);
		if (balance === null) {
			return;
		}
		const balanceCents = Math.round(balance * 100);
		// Save balance snapshot to DB but only if it's changed since the last time we got the info
		await BalanceSnapshotRepository.createIfChanged(
			{
				customerId: customer.id,
				balanceSnapshotType: EBalanceSnapshotType.K401,
				amountCents: balanceCents,
			},
			t
		);
	}

	// Recalculates the customer's ESPP balance
	public static async updateEsppBalance(customer: Customer, t?: TTransaction) {
		// The ESPP balance is equal to what's in the customer's ESPP account(s), we use Plaid to get that info
		const balance = await PlaidService.getCustomerBalance(
			customer,
			EPlaidConnectionType.Espp,
			t
		);
		if (balance === null) {
			return;
		}
		const balanceCents = Math.round(balance * 100);
		// Save balance snapshot to DB but only if it's changed since the last time we got the info
		await BalanceSnapshotRepository.createIfChanged(
			{
				customerId: customer.id,
				balanceSnapshotType: EBalanceSnapshotType.Espp,
				amountCents: balanceCents,
			},
			t
		);
	}

	// Recalculates the customer's checking account balance
	public static async updateCheckingBalance(
		customer: Customer,
		t?: TTransaction
	) {
		// The ESPP balance is equal to what's in the customer's checking account(s), we use Plaid to get that info
		const balance = await PlaidService.getCustomerBalance(
			customer,
			EPlaidConnectionType.Checking,
			t
		);
		if (balance === null) {
			return;
		}
		const balanceCents = Math.round(balance * 100);
		// Save balance snapshot to DB but only if it's changed since the last time we got the info
		await BalanceSnapshotRepository.createIfChanged(
			{
				customerId: customer.id,
				balanceSnapshotType: EBalanceSnapshotType.Checking,
				amountCents: balanceCents,
			},
			t
		);
	}

	public static async updateAllLendtableBalances() {
		logger.warn("updateAllLendtableBalances - started");
		const customers = await CustomerRepository.getAllSignedUp();
		for (const { id } of customers) {
			try {
				await withTransaction(async (t) => {
					const customer = await CustomerRepository.getById(id, t);
					if (!customer) {
						return;
					}
					await this.updateLendtableBalance(customer, t);
				});
			} catch (err) {
				logger.error("BalancesService.updateAllLendtableBalances", err);
			}
		}
		logger.warn("updateAllLendtableBalances - complete");
	}

	public static async updateAllK401Balances() {
		logger.info("updateAllK401Balances - started");
		const connectionsK401 = await PlaidConnectionRepository.getAllByType(
			EPlaidConnectionType.K401
		);
		for (const { id } of connectionsK401) {
			HotShot.increment("BalancesService.updateAllK4O1Balances", {
				service: "cronjob",
				api: "plaid",
			});
			try {
				await withTransaction(async (t) => {
					const connection = await PlaidConnectionRepository.getById(id, t);
					if (!connection) {
						return;
					}
					const customer = await CustomerRepository.getById(
						connection.customerId,
						t
					);
					if (!customer) {
						return;
					}
					await this.updateK401Balance(customer, t);
				});
			} catch (err) {
				logger.warn("BalancesService.updateAllK401Balances", err);
				HotShot.increment("BalancesService.updateAllK4O1Balances_error", {
					service: "cronjob",
					api: "plaid",
				});
				HotShot.event(
					"BalancesService.updateAllK401Balances_error",
					`Error updating 401K balances for Plaid Connection: ${id}`,
					{
						aggregation_key: "cronjob",
						date_happened: new Date(),
						alert_type: "error",
					}
				);
			}
		}
		logger.info("updateAllK401Balances - complete");
	}

	public static async updateAllEsppBalances() {
		logger.info("updateAllEsppBalances - started");
		const connectionsEspp = await PlaidConnectionRepository.getAllByType(
			EPlaidConnectionType.Espp
		);
		for (const { id } of connectionsEspp) {
			HotShot.increment("BalancesService.updateAllEsppBalances", {
				service: "cronjob",
				api: "plaid",
			});
			try {
				await withTransaction(async (t) => {
					const connection = await PlaidConnectionRepository.getById(id, t);
					if (!connection) {
						return;
					}
					const customer = await CustomerRepository.getById(
						connection.customerId,
						t
					);
					if (!customer) {
						return;
					}
					await this.updateEsppBalance(customer, t);
				});
			} catch (err) {
				logger.warn("BalancesService.updateAllEsppBalances", err);
				HotShot.increment("BalancesService.updateAllEsppBalances_error", {
					service: "cronjob",
					api: "plaid",
				});
				HotShot.event(
					"BalancesService.updateAllEsppBalances_error",
					`Error updating ESPP balances for Plaid Connection: ${id}`,
					{
						aggregation_key: "cronjob",
						date_happened: new Date(),
						alert_type: "error",
					}
				);
			}
		}
		logger.info("updateAllEsppBalances - complete");
	}

	public static async updateAllCheckingBalances() {
		logger.info("updateAllCheckingBalances - started");
		const connectionsChecking = await PlaidConnectionRepository.getAllByType(
			EPlaidConnectionType.Checking
		);
		for (const { id } of connectionsChecking) {
			HotShot.increment("BalancesService.updateAllCheckingBalances", {
				service: "cronjob",
				api: "plaid",
			});
			try {
				await withTransaction(async (t) => {
					const connection = await PlaidConnectionRepository.getById(id, t);
					if (!connection) {
						return;
					}
					const customer = await CustomerRepository.getById(
						connection.customerId,
						t
					);
					if (!customer) {
						return;
					}
					await this.updateCheckingBalance(customer, t);
				});
			} catch (err) {
				logger.warn("BalancesService.updateAllCheckingBalances", err);
				HotShot.increment("BalancesService.updateAllCheckingBalances_error", {
					service: "cronjob",
					api: "plaid",
				});
				HotShot.event(
					"BalancesService.updateAllCheckingBalances_error",
					`Error updating checking balances for Plaid Connection: ${id}`,
					{
						aggregation_key: "cronjob",
						date_happened: new Date(),
						alert_type: "error",
					}
				);
			}
		}
		logger.info("updateAllCheckingBalances - complete");
	}
}

export default BalancesService;
// src/components/RadixSlider.jsx
import * as Slider from "@radix-ui/react-slider";
import { useState } from "react";

const RadixSlider = () => {
  const [values, setValues] = useState([20, 80]);
  console.log(values);
  return (
    <div className="bg-gray-200 ">
      <label
        htmlFor="slider"
        className="text-center text-sm font-medium text-gray-700"
      >
        range: {values.toString()}
      </label>
      <Slider.Root
        id="slider"
        className="outline outline-1 mx-auto relative flex items-center select-none touch-none w-[300px] h-5"
        defaultValue={values}
        // onValueChange={(values) => setValues(values)}
        onValueCommit={(values) => setValues(values)}
        max={100}
        step={1}
        minStepsBetweenThumbs={10}
      >
        <Slider.Track className="bg-blue-400 relative grow rounded-full h-[3px]">
          <Slider.Range className="absolute bg-red-400 rounded-full h-full" />
        </Slider.Track>
        <Slider.Thumb
          className="block bg-white shadow-[0_2px_10px] shadow-black rounded-full hover:bg-violet-300 focus:outline "
          aria-label="Volume"
          asChild
        >
          <p className=" px-1"> {values[0]}</p>
        </Slider.Thumb>
        <Slider.Thumb
          className="block   bg-white shadow-[0_2px_10px] shadow-black rounded-full hover:bg-violet-300 focus:outline "
          aria-label="Volume"
          asChild
        >
          <p className=" px-1"> {values[1]}</p>
        </Slider.Thumb>
      </Slider.Root>
    </div>
  );
};

export default RadixSlider;

// src/App.jsx
const App = () => (
  <div>

      <RadixSlider />
     
    </div>
  </div>
);
import { zodResolver } from "@hookform/resolvers/zod";
import { useState } from "react";
import { useForm } from "react-hook-form";
import { z } from "zod";

const signUpSchema = z
  .object({
    email: z
      .string()
      .nonempty("email is required")
      .email("Invalid email address"),
    password: z.string().min(8, "Password must be at least 8 characters"),
    confirmPassword: z.string(),
  })
  // we can use zod to validate using refine method
  .refine((data) => data.password === data.confirmPassword, {
    message: "Passwords do not match",
    path: ["confirmPassword"], // it will show error in confirmPassword field
  });

type ISignUpSchema = z.infer<typeof signUpSchema>; // create type from schema

const ReactHookFormWithZod = () => {
  const [show, setShow] = useState(false);
  const [show1, setShow1] = useState(false);
  const { register, handleSubmit, formState, reset } = useForm<ISignUpSchema>({
    resolver: zodResolver(signUpSchema), //tell which schema to resolve
  });
  const { errors, isSubmitting } = formState;

  const onSubmit = async (data: ISignUpSchema) => {
    console.log(data);
    //-------send data to server----------//
    await new Promise((resolve) => setTimeout(resolve, 1000));
    //------
    reset(); // clear form
  };
  return (
    <form
      onSubmit={handleSubmit(onSubmit)}
      className="flex flex-col gap-y-4 [&>div>input]:w-full"
    >
      <label className="-mb-3 text-sm text-gray-500" htmlFor="email">
        email
      </label>
      <div className="">
        <input
          {...register("email")}
          type="text"
          placeholder="email"
          className="rounded border px-4 py-2"
        />
        {
          // granular show errors
          errors.email && (
            <p className="text-sm text-red-500">{`${errors.email.message}`}</p>
          )
        }
      </div>
      <label className="-mb-3 text-sm text-gray-500" htmlFor="password">
        password
      </label>
      <div className="relative ">
        <input
          {...register("password")}
          type={show ? "text" : "password"}
          id="password"
          placeholder="password"
          className=" block rounded border py-2 pl-2 pr-12"
        ></input>
        <p
          className="absolute  right-2 top-0 block cursor-pointer select-none py-2 "
          onClick={() => setShow((show) => !show)}
        >
          👁️
        </p>
        {
          // granular show errors
          errors.password && (
            <p className="text-sm text-red-500">{`${errors.password.message}`}</p>
          )
        }
      </div>
      <label className="-mb-3 text-sm text-gray-500" htmlFor="confirmPassword ">
        confirm password
      </label>
      <div className="relative">
        <input
          {...register("confirmPassword")}
          id="confirmPassword"
          type={show1 ? "text" : "password"}
          placeholder="confirm password"
          className="rounded border py-2 pl-2 pr-10 "
        />
        <p
          className="absolute  right-2 top-0 block cursor-pointer select-none py-2 "
          onClick={() => setShow1((show) => !show)}
        >
          👁️
        </p>
        {
          // granular show errors
          errors.confirmPassword && (
            <p className="text-sm text-red-500">{`${errors.confirmPassword.message}`}</p>
          )
        }
      </div>

      <button
        type="submit"
        className="rounded bg-blue-500 py-2 text-white disabled:cursor-no-drop disabled:bg-gray-500"
        disabled={isSubmitting}
      >
        {isSubmitting ? "loading..." : "Submit"}
      </button>
    </form>
  );
};

export default ReactHookFormWithZod;
import React, { useState } from "react";
import { useForm } from "react-hook-form";
import type { FieldValues } from "react-hook-form";

const ReactHookForm = () => {
  const [show, setShow] = useState(false);
  const [show1, setShow1] = useState(false);
  const { register, handleSubmit, formState, reset, getValues } = useForm();
  const { errors, isSubmitting } = formState;

  const onSubmit = async (data: FieldValues) => {
    // (data:FieldValues) type is -> {[x:string] : any} //we would need zod for more typesafety
    console.log(data);
    //-------send data to server----------//
    await new Promise((resolve) => setTimeout(resolve, 1000));
    //------
    reset(); // clear form
  };
  return (
    <form
      onSubmit={handleSubmit(onSubmit)}
      className="flex flex-col gap-y-4 [&>div>input]:w-full"
    >
      <label className="-mb-3 text-sm text-gray-500" htmlFor="email">
        email
      </label>
      <div className="border">
        <input
          {...register("email", {
            required: "Email is required",
            pattern: {
              value: /\S+@\S+\.\S+/,
              message: "invaid email format",
            },
          })}
          type="email"
          placeholder="email"
          className="rounded px-4 py-2"
        />
        {
          // granular show errors
          errors.email && (
            <p className="text-sm text-red-500">{`${errors.email.message}`}</p>
          )
        }
      </div>
      <label className="-mb-3 text-sm text-gray-500" htmlFor="password">
        password
      </label>
      <div className="relative border ">
        <input
          {...register("password", {
            required: "Password is required",
            minLength: {
              value: 8,
              message: "Password must be at least 8 characters",
            },
          })}
          type={show ? "text" : "password"}
          id="password"
          placeholder="password"
          className="  block rounded py-2 pl-2 pr-12"
        ></input>
        <p
          className="absolute  right-2 top-0 block cursor-pointer select-none py-2 "
          onClick={() => setShow((show) => !show)}
        >
          👁️
        </p>
        {
          // granular show errors
          errors.password && (
            <p className="text-sm text-red-500">{`${errors.password.message}`}</p>
          )
        }
      </div>
      <label className="-mb-3 text-sm text-gray-500" htmlFor="confirmPassword ">
        confirm password
      </label>
      <div className="relative border">
        <input
          {...register("confirmPassword", {
            required: "Confirm Password is required",
            validate: (value) => {
              return (
                // getValues from "password" input
                value === getValues("password") || "Passwords do not match"
              );
            },
          })}
          id="confirmPassword"
          type={show1 ? "text" : "password"}
          placeholder="confirm password"
          className="rounded py-2 pl-2 pr-10 "
        />
        <p
          className="absolute  right-2 top-0 block cursor-pointer select-none py-2 "
          onClick={() => setShow1((show) => !show)}
        >
          👁️
        </p>
        {
          // granular show errors
          errors.confirmPassword && (
            <p className="text-sm text-red-500">{`${errors.confirmPassword.message}`}</p>
          )
        }
      </div>

      <button
        type="submit"
        className="rounded bg-blue-500 py-2 text-white disabled:cursor-no-drop disabled:bg-gray-500"
        disabled={isSubmitting}
      >
        {isSubmitting ? "loading..." : "Submit"}
      </button>
    </form>
  );
};

export default ReactHookForm;
import { useState } from "react";

const initialFormData = {
  email: "",
  password: "",
  confirmPassword: "",
};
const FormWithoutReactHookForm = () => {
  const [show, setShow] = useState(false);
  const [show1, setShow1] = useState(false);
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [errors, setErrors] = useState<string[]>([""]); // errors are array of strings
  const [formData, setFormData] = useState(initialFormData);

  const handleSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    setErrors([]); // clear errors
    //-------validate data ----------//
    if (formData.password !== formData.confirmPassword) {
      setErrors((prev) => [...prev, "passwords do not match"]);
      return;
    }

    console.log(formData);
    setIsSubmitting(true); // show loading or disable submit button
    //-------send data to Server ----------//
    await new Promise((resolve) => setTimeout(resolve, 1000));
    //....
    setFormData(initialFormData); // clear form
    setIsSubmitting(false);
  };
  return (
    <form
      className="flex flex-col gap-y-4 [&>div>input]:w-full"
      onSubmit={handleSubmit}
    >
      <label className="-mb-3 text-sm text-gray-500" htmlFor="email">
        email
      </label>
      <div className="border">
        <input
          type="email"
          id="email"
          required={true}
          placeholder="email"
          className="rounded px-4 py-2"
          value={formData.email}
          onChange={(e) =>
            setFormData((prev) => ({ ...prev, email: e.target.value }))
          }
        />
      </div>
      <label className="-mb-3 text-sm text-gray-500" htmlFor="password">
        password
      </label>
      <div className="relative border ">
        <input
          type={show ? "text" : "password"}
          id="password"
          placeholder="password"
          className="  block rounded py-2 pl-2 pr-12"
          required={true}
          minLength={8}
          value={formData.password}
          onChange={(e) =>
            setFormData((prev) => ({ ...prev, password: e.target.value }))
          }
        ></input>
        <p
          className="absolute  right-2 top-0 block cursor-pointer select-none py-2 "
          onClick={() => setShow((show) => !show)}
        >
          👁️
        </p>
      </div>
      <label className="-mb-3 text-sm text-gray-500" htmlFor="confirmPassword ">
        confirm password
      </label>
      <div className="relative border">
        <input
          id="confirmPassword"
          required={true}
          type={show1 ? "text" : "password"}
          placeholder="confirm password"
          className="rounded py-2 pl-2 pr-10 "
          value={formData.confirmPassword}
          onChange={(e) =>
            setFormData((prev) => ({
              ...prev,
              confirmPassword: e.target.value,
            }))
          }
        />
        <p
          className="absolute  right-2 top-0 block cursor-pointer select-none py-2 "
          onClick={() => setShow1((show) => !show)}
        >
          👁️
        </p>
      </div>
      {
        // show errors
        errors.length > 0 && (
          <div className=" text-center text-red-500">
            {errors.map((error, i) => (
              <p key={i} className="text-sm">
                {error}
              </p>
            ))}
          </div>
        )
      }
      <button
        type="submit"
        className="rounded bg-blue-500 py-2 text-white disabled:cursor-no-drop disabled:bg-gray-500"
        disabled={isSubmitting}
      >
        {isSubmitting ? "loading..." : "Submit"}
      </button>
    </form>
  );
};

export default FormWithoutReactHookForm;
// Add a new FormControl to handle file uploads
chatForm = new FormGroup({
  message: new FormControl('', [Validators.required]),
  file: new FormControl(null),
});

// Add a new method to handle file uploads
onFileChange(event: any) {
  if (event.target.files.length > 0) {
    const file = event.target.files[0];
    this.chatForm.patchValue({
      file: file,
    });
  }
}

// Modify the sendMessage method to handle file uploads
sendMessage() {
  const sentMessage = this.chatForm.value.message!;
  const sentFile = this.chatForm.value.file;
  this.loading = true;
  this.messages.push({
    type: 'user',
    message: sentMessage,
  });
  this.chatForm.reset();
  this.scrollToBottom();
  
  // Handle file uploads
  if (sentFile) {
    // Add logic to handle file uploads here
    // For example, you could send the file to your server and then send the URL to RASA
  } else {
    this.messageService.sendMessage(sentMessage).subscribe((response: any) => {
      for (const obj of response) {
        let value;
        console.log(obj);
        if (obj.hasOwnProperty('text')) {
          value = obj['text'];
          this.pushMessage(value);
        }
        if (obj.hasOwnProperty('image')) {
          value = obj['image'];
          this.pushMessage(value);
        }
      }
      // MANIPULATION OF DATA TYPES OF RASA SUCH AS IMAGE, TEXT, BUTTONS, ETC
    }, (error) => { console.log(error); });
  }
}
sendMessage() {
  const sentMessage = this.chatForm.value.message!;
  this.loading = true;
  this.messages.push({
    type: 'user',
    message: sentMessage,
  });
  this.chatForm.reset();
  this.scrollToBottom();
  this.messageService.sendMessage(sentMessage).subscribe((response: any) => {
    for (const obj of response) {
      let value;
      console.log(obj);
      if (obj.hasOwnProperty('text')) {
        value = obj['text'];
        this.pushMessage(value);
      }
      if (obj.hasOwnProperty('image')) {
        value = obj['image'];
        this.pushMessage(value);
      }
      // Handle buttons
      if (obj.hasOwnProperty('buttons')) {
        value = obj['buttons'];
        // Add logic to handle buttons here
      }
      // Handle custom payloads
      if (obj.hasOwnProperty('custom')) {
        value = obj['custom'];
        // Add logic to handle custom payloads here
      }
    }
    // MANIPULATION OF DATA TYPES OF RASA SUCH AS IMAGE, TEXT, BUTTONS, ETC
  }, (error) => { console.log(error); });
}
import { Component, ViewChild } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { MessageService } from '../service/api.service';

export interface Message {
  type: string;
  message: string;
}

@Component({
  selector: 'app-chat-support',
  templateUrl: './chat-support.component.html',
  styleUrls: ['./chat-support.component.scss'],
})
export class ChatSupportComponent {
  isOpen = false;
  loading = false;
  messages: Message[] = [];
  chatForm = new FormGroup({
    message: new FormControl('', [Validators.required]),
  });
  @ViewChild('scrollMe') private myScrollContainer: any;

  constructor(private messageService: MessageService) {
  }

  openSupportPopup() {
    this.isOpen = !this.isOpen;
  }

  sendMessage() {
    const sentMessage = this.chatForm.value.message!;
    this.loading = true;
    this.messages.push({
      type: 'user',
      message: sentMessage,
    });
    this.chatForm.reset();
    this.scrollToBottom();
    this.messageService.sendMessage(sentMessage).subscribe((response: any) => {
      for (const obj of response) {
        if (obj.hasOwnProperty('text')) {
          const value = obj['text'];
          this.pushMessage('text', value); // Specify the type as 'text'
        }
        if (obj.hasOwnProperty('image')) {
          const value = obj['image'];
          this.pushMessage('image', value); // Specify the type as 'image'
        }
        // Add more conditions for other types like buttons, cards, etc.
      }
    }, (error) => {
      console.log(error);
    });
  }

  pushMessage(type: string, message: string) {
    console.log(message);
    setTimeout(() => {
      this.messages.push({
        type: 'client',
        message: message,
      });
      this.loading = false;
      this.scrollToBottom();
    }, 150);
  }

  scrollToBottom() {
    setTimeout(() => {
      try {
        this.myScrollContainer.nativeElement.scrollTop =
          this.myScrollContainer.nativeElement.scrollHeight + 500;
      } catch (err) {
      }
    }, 150);
  }
}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
  providedIn: 'root',
})
export class MessageService {
  constructor(private http: HttpClient) {}

  sendMessage(message: string) {
    return this.http.post('http://localhost:5005/webhooks/rest/webhook', { message: message });
  }
}
import { Component, ViewChild } from '@angular/core';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { MessageService } from '../service/api.service';

export interface Message {
  type: string;
  message: string;
}

@Component({
  selector: 'app-chat-support',
  templateUrl: './chat-support.component.html',
  styleUrls: ['./chat-support.component.scss'],
})
export class ChatSupportComponent {
  isOpen = false;
  loading = false;
  messages: Message[] = [];
  chatForm = new FormGroup({
    message: new FormControl('', [Validators.required]),
  });
  @ViewChild('scrollMe') private myScrollContainer: any;

  constructor(private messageService: MessageService) {
  }

  openSupportPopup() {
    this.isOpen = !this.isOpen;
  }

  sendMessage() {
    const sentMessage = this.chatForm.value.message!;
    this.loading = true;
    this.messages.push({
      type: 'user',
      message: sentMessage,
    });
    this.chatForm.reset();
    this.scrollToBottom();
    this.messageService.sendMessage(sentMessage).subscribe((response: any) => {
      for (const obj of response) {
        let value
        console.log(obj);
        if (obj.hasOwnProperty('text') ) {
          value = obj['text']
          this.pushMessage(value)

        }
        if (obj.hasOwnProperty('image') ) {
          value = obj['image']
          this.pushMessage(value)
        }
      }
      //MANIPULATION OF DATA TYPES OF RASA SUCH A IMAGE, TEXT, BUTTONS, ETC
    }
    , (error) => { console.log(error)});
  }

  pushMessage(message:string){

    console.log(message);
     setTimeout(() =>{this.messages.push({
      type: 'client',
      message: message,
    });
    this.loading = false;
    this.scrollToBottom();
  }, 150)
  }

  scrollToBottom() {
    setTimeout(() => {
      try {
        this.myScrollContainer.nativeElement.scrollTop =
          this.myScrollContainer.nativeElement.scrollHeight + 500;
      } catch (err) {}
    }, 150);
  }
}
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { Chart,registerables } from 'node_modules/chart.js';
import { RegionService } from '../service/region.service';
import { RegionModel } from '../service/Models/regionsModel';


Chart.register(...registerables);

@Component({
  selector: 'app-charts',
  templateUrl: './charts.component.html',
  styleUrls: ['./charts.component.css']
})

export class ChartsComponent implements OnInit{

  data: any;
  @ViewChild('myTemp')
  myTempRef!: ElementRef;

 
  constructor(private regionService : RegionService) {}
  
  ngOnInit(): void {
    this.regionService.getRegions().subscribe(response => {
      let regionList = response;

      this.data = response.$values;
      
      this.populateChartData(this.data);
      console.log('data',regionList)
      return regionList
    });
  }

  populateChartData(data: RegionModel[]) {
    
    let labelsData: string [] = [];
    let labelsPopulation: number [] = [];
    
    data.forEach((element: any) => {
      labelsData.push(element.code);
      labelsPopulation.push(element.population)
    });


    new Chart("barchart", {
      type: 'bar',
      data: {
        labels: labelsData,
        datasets: [{
          label: '# of Population',
          data: labelsPopulation,
          borderWidth: 1
        }]
      },
      
      options: {
        scales: {
          y: {
            beginAtZero: true
          },
        }
      
      }
    });
    

    new Chart("piechart", {
      type: 'pie',
      data: {
        labels: labelsData,
        datasets: [{
          label: '# of Population',
          data: labelsPopulation,
          borderWidth: 1
        }]
      },
      options: {
        scales: {
          y: {
            beginAtZero: true
          }
        }
      }
    });

    new Chart("dochart", {
      type: 'doughnut',
      data: {
        labels: labelsData,
        datasets: [{
          label: '# of Population',
          data: labelsPopulation,
          borderWidth: 1
        }]
      },
      options: {
        scales: {
          y: {
            beginAtZero: true
          }
        }
      }
    });

    new Chart("pochart", {
      type: 'polarArea',
      data: {
        labels: labelsData,
        datasets: [{
          label: '# of Population',
          data: labelsPopulation,
          borderWidth: 1
        }]
      },
      options: {
        scales: {
          y: {
            beginAtZero: true
          }
        }
      }
    });

    new Chart("rochart", {
      type: 'radar',
      data: {
        labels: labelsData,
        datasets: [{
          label: '# of Population',
          data: labelsPopulation,
          borderWidth: 1
        }]
      },
      options: {
        scales: {
          y: {
            beginAtZero: true
          }
        }
      }
    });

    new Chart("linechart", {
      type: 'line',
      data: {
        labels: labelsData,
        datasets: [{
          label: '# of Population',
          data: labelsPopulation,
          borderWidth: 1
          
        }]
        
      },
      options: {
        scales: {
          y: {
            beginAtZero: true
          }
        }
      }
    });

    new Chart("bubchart", {
      type: 'bubble',
      data: {
        labels: labelsData,
        datasets: [{
          label: '# of Population',
          data: labelsPopulation,
          borderWidth: 1
          
        }]
        
      },
      options: {
        scales: {
          y: {
            beginAtZero: true
          }
        }
      }
    });

  }
  
}
import { Injectable } from '@angular/core';
import { Observable, map, of} from 'rxjs';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { RegisterUser } from '../shared/register-user';
import { LoginUser } from '../shared/login-user';
import { User } from '../shared/user';
import { Product } from '../shared/product';

@Injectable({
  providedIn: 'root'
})

export class APIService {

apiUrl = 'http://localhost:5240/api/'

httpOptions ={
  headers: new HttpHeaders({
    ContentType: 'application/json'
  })
}
  constructor(private httpClient: HttpClient) {
  }

  RegisterUser(registerUser: RegisterUser){
    return this.httpClient.post(`${this.apiUrl}Authentication/Register`, registerUser, this.httpOptions)
  }

  getProducts() {
    return this.httpClient.get(`${this.apiUrl}Store/ProductListing`)
    .pipe(map(result => result))
  }

  LoginUser(loginUser: LoginUser){
    return this.httpClient.post<User>(`${this.apiUrl}Authentication/Login`, loginUser, this.httpOptions)
  }

  addProduct(file:FormData){
    
    return this.httpClient.post(`${this.apiUrl}Store/AddProduct`, file)
  }

  getBrands(): Observable<any>
  {
    return this.httpClient.get(`${this.apiUrl}Store/Brands`)
    .pipe(map(result => result))
  }

  getProductTypes(): Observable<any>
  {
    return this.httpClient.get(`${this.apiUrl}Store/ProductTypes`)
    .pipe(map(result => result))
  }
}
import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { APIService } from '../services/api.service';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { MatSnackBar } from '@angular/material/snack-bar';
import { HttpErrorResponse } from '@angular/common/http';

@Component({
  selector: 'app-login',
  templateUrl: './login.component.html',
  styleUrls: ['./login.component.scss']
})
export class LoginComponent implements OnInit {

  loginFormGroup: FormGroup = this.fb.group({
    emailaddress: ['', [Validators.required, Validators.email]],
    password: ['', Validators.required],
  })

  isLoading:boolean = false

  constructor(private router: Router, private apiService: APIService, private fb: FormBuilder, private snackBar: MatSnackBar) { }

  ngOnInit(): void {
  }

  async LoginUser(){
    if(this.loginFormGroup.valid)
    {
      this.isLoading = true

      await this.apiService.LoginUser(this.loginFormGroup.value).subscribe(result => {
        localStorage.setItem('User', JSON.stringify(result))
        this.loginFormGroup.reset();
        this.router.navigateByUrl('productListing');
      })
    }
  }

}
<div class="login-wrapper" fxLayout="row" fxLayoutAlign="center center">
    <mat-card class="box" *ngIf="!isLoading">
      <mat-card-header>
        <mat-card-title>Log in</mat-card-title>
      </mat-card-header>
      <form class="form" [formGroup]="loginFormGroup">
        <mat-card-content>
          <mat-form-field class="full-width">
            <mat-label>Username</mat-label>
            <input matInput placeholder="Enter the User's Email address" formControlName="emailaddress">
          </mat-form-field>
          <mat-form-field class="full-width">
            <mat-label>Password</mat-label>
            <input matInput type="password" placeholder="Enter the User's Password" formControlName="password">
          </mat-form-field>
        </mat-card-content>
        <button mat-stroked-button color="primary" class="btn-block" (click)="LoginUser()">Log in</button>
        <div>Don't have an account? Register <a [routerLink]="['../register']">here</a></div>
      </form>
    </mat-card>
    <mat-progress-spinner mode="indeterminate" value="50" *ngIf="isLoading">
    </mat-progress-spinner>
  </div>
import { Component, OnInit } from '@angular/core';
import { Restaurant } from 'src/app/models/restaurant.model';
import { ApiService } from 'src/app/services/api/api.service';

@Component({
  selector: 'app-home',
  templateUrl: './home.page.html',
  styleUrls: ['./home.page.scss'],
})
export class HomePage implements OnInit {

  banners: any[] = [];
  restaurants: Restaurant[] = [];
  isLoading: boolean = false;

  constructor(
    private api: ApiService
  ) { }

  ngOnInit() {
    this.isLoading = true;
    setTimeout(() => {  
      this.banners = this.api.banners;
      this.restaurants = this.api.restaurants;
      this.isLoading = false;
    }, 3000);
    
  }

}
 import { CommonModule } from '@angular/common';
 import { FormsModule } from '@angular/forms';
 import { IonicModule } from '@ionic/angular';
 import { Component, ViewChild } from '@angular/core';
 import { IonModal } from '@ionic/angular';
 import { OverlayEventDetail } from '@ionic/core/components';

@Component({
  selector: 'app-account',
  templateUrl: './account.page.html',
  styleUrls: ['./account.page.scss'],
  standalone: true,
  imports: [IonicModule, CommonModule, FormsModule],
  
})
export class AccountPage {
 
  @ViewChild(IonModal) modal!: IonModal;

  dishPrice: string = '';
  restaurantName!: string;
  dishName!: string;
  quantity!:string;
  orderHistory: any[] = [];
  userName: string = 'John Doe';
  userEmail: string = 'johndoe@gmail.com';
  userNumber: string = '012 345 6789';
  totalPrice: number =0;
  itemPrice: number =0;
  
  ionViewWillEnter() {
    // retrieve cart items from local storage
    this.orderHistory = JSON.parse(localStorage.getItem('paidList') ?? "paidList");
    const cartItems = JSON.parse(localStorage.getItem('paidList') ?? "[]");
    
    if (this.orderHistory != null) {
      this.orderHistory = cartItems;
      this.calculateTotalPrice();
    }
  };

  calculateTotalPrice() {
    let totalPrice = 0;
    let itemPrice = 0;

      for (let item of this.orderHistory) {
        itemPrice += item.dishPrice * item.quantity;
      }
      // add delivery fee to the total price
      totalPrice = itemPrice + 50;
      this.totalPrice = totalPrice;
      this.itemPrice = itemPrice;
    }

  cancel() {
    this.modal.dismiss(null, 'cancel');
  }

  async canDismiss(data?: any, role?: string) {
    return role !== 'gesture';
  }

  confirm() {
    this.modal.dismiss({name: this.userName, email: this.userEmail, number: this.userNumber}, 'confirm');
    this.modal   
  }

  onWillDismiss(event: Event) {
    const ev = event as CustomEvent<OverlayEventDetail<{name:string, email:string, number:string}>>;
    if (ev.detail.role === 'confirm') {
      if(ev.detail.data){
        this.userName = `${ev.detail.data.name}`;
        this.userEmail = `${ev.detail.data.email}`;
        this.userNumber = `${ev.detail.data.number}`;
      }
      else
      {
        console.log('undefined')
      }
    }

  }

  reOrderAddToCart(){
  // Retrieve the orderList from local storage
  const orderList = JSON.parse(localStorage.getItem('paidList') ?? '[]');

  // Store the orderList in the paidList array
  localStorage.setItem('orderList', JSON.stringify(orderList));

  // Clear the orderList array in local storage
  localStorage.setItem('paidList', JSON.stringify([]));

  setTimeout(() => {
    const orderCards = document.querySelectorAll('.orderHistory-card');
    orderCards.forEach(card => card.remove());
  }, 100);

  }

 
}

<div class="ion-page" #page>
<ion-content [fullscreen]="true" class="ion-padding">
  <ion-header>
    <ion-toolbar>
      <ion-title>Account</ion-title>
    </ion-toolbar>
  </ion-header>
        <ion-list>
          <ion-item> 
            <ion-label>{{userName}} <br>                
              <ion-text color="medium">
                <sub><ion-icon name="call"></ion-icon>{{userNumber}}</sub>
                <sub>  |  </sub>
                <sub><ion-icon name="mail"></ion-icon>{{userEmail}}</sub>
              </ion-text>
            </ion-label>
            <ion-button slot="end" fill="outline" size="small" id="open-modal" expand="block">Edit</ion-button>
          </ion-item>
        </ion-list>
        <ion-grid>
          <ion-row class="ion-text-center">
            <ion-col size="auto">
              <ion-icon style="padding-top: 12px;" aria-hidden="true" name="home" size="large"></ion-icon>
            </ion-col>
            <ion-col>
              <h3><ion-text>Manage Address</ion-text></h3>
            </ion-col>
            <ion-col size="auto">
              <ion-button fill="clear"><ion-icon size="large" name="chevron-forward-circle-outline"></ion-icon></ion-button>
            </ion-col>
          </ion-row>
        </ion-grid>

        <ion-modal trigger="open-modal" (willDismiss)="onWillDismiss($event)">
          <ng-template>
            <ion-header>
              <ion-toolbar>
                <ion-buttons slot="start">
                  <ion-button (click)="cancel()">Cancel</ion-button>
                </ion-buttons>
                <ion-title>Edit</ion-title>
                <ion-buttons slot="end">
                  <ion-button (click)="confirm()" [strong]="true">Confirm</ion-button>
                </ion-buttons>
              </ion-toolbar>
            </ion-header>
            <ion-content class="ion-padding">
              <ion-item>
                <ion-label position="stacked">Enter your name</ion-label>
                <ion-input type="text" placeholder="Your name"[(ngModel)] = "userName"></ion-input>
                <ion-label position="stacked">Enter your email</ion-label>
                <ion-input type="text" placeholder="Your email"[(ngModel)] = "userEmail"></ion-input>
                <ion-label position="stacked">Enter your number</ion-label>
                <ion-input type="text" placeholder="Your number"[(ngModel)] = "userNumber"></ion-input>
              </ion-item>
            </ion-content>
          </ng-template>
        </ion-modal>

  <ion-card>
    <ion-card-header color="primary">
      <ion-card-title>Order History</ion-card-title>
    </ion-card-header>
   <br>
    <ion-card-content  *ngFor="let item of orderHistory">
      <ion-list class="orderHistory-card">
        <ion-item>
          <h2><ion-label>{{ item.restaurantName }} </ion-label></h2>
        </ion-item>
        <ion-item>
          <ion-label>Dish: {{ item.dishName }}</ion-label>
        </ion-item>
        <ion-item>
          <ion-label>Quantity: {{ item.quantity }}</ion-label>
        </ion-item>
      </ion-list>
    </ion-card-content>
    <ion-card-content>
      <ion-text color="primary">
        <h1>Total: {{ totalPrice | currency :'ZAR':'symbol'}}</h1>
      </ion-text>
      <ion-text color="secondary">
        <sub>Includes delivery fee</sub>
      </ion-text>
    </ion-card-content>
  </ion-card>

  <ion-grid>
    <ion-row>
      <ion-col>
        <ion-button style="width: 100%;" fill="outline" size="small" (click)="reOrderAddToCart()">Reorder All</ion-button>
      </ion-col>
      <ion-col>
        <ion-button style="width: 100%;" fill="outline" size="small"  id="open-help-modal" expand="block">Need Help?</ion-button>
      </ion-col>
    </ion-row>
  </ion-grid>

  <ion-modal #modal trigger="open-help-modal" [canDismiss]="canDismiss" [presentingElement]="page">
    <ng-template>
      <ion-header>
        <ion-toolbar>
          <ion-title>Modal</ion-title>
          <ion-buttons slot="end">
            <ion-button (click)="modal.dismiss()">Close</ion-button>
          </ion-buttons>
        </ion-toolbar>
      </ion-header>
      <ion-content class="ion-padding">
        <h1>
          Placing an order:
        </h1>
        <p>
          To place an order, simply search for the restaurant or cuisine you're interested in, browse their menu, and select the items you'd like to order. Once you're done, proceed to the checkout page and review your order details before submitting.
        </p>
        <h1>
          Making a payment:
        </h1>
        <p>
          We offer a variety of payment options, including credit/debit card, PayPal, and in-app wallet. Simply select your preferred payment method at checkout and follow the instructions to complete your transaction.
        </p>
        <h1>
          Changing delivery address:
        </h1>
        <p>
          If you need to change your delivery address after placing an order, please contact our support team as soon as possible. We'll do our best to accommodate your request, but please note that any changes made after the order has been dispatched may result in a delay or additional fee.
        </p>
        <h1>
          Changing user details:
        </h1>
        <p>
          To update your user details, including your name, email, phone number, or password, go to your account settings page and make the necessary changes. Please note that some details, such as your email or phone number, may be required for verification purposes and cannot be changed without additional steps.
        </p>
      </ion-content>
    </ng-template>
  </ion-modal>
</ion-content>
</div>



<div class="ion-page" #page>
<ion-content [fullscreen]="true" class="ion-padding">
  <ion-header>
    <ion-toolbar>
      <ion-title>Account</ion-title>
    </ion-toolbar>
  </ion-header>
        <ion-list>
          <ion-item> 
            <ion-label>{{userName}} <br>                
              <ion-text color="medium">
                <sub><ion-icon name="call"></ion-icon>{{userNumber}}</sub>
                <sub>  |  </sub>
                <sub><ion-icon name="mail"></ion-icon>{{userEmail}}</sub>
              </ion-text>
            </ion-label>
            <ion-button slot="end" fill="outline" size="small" id="open-modal" expand="block">Edit</ion-button>
          </ion-item>
        </ion-list>
        <ion-grid>
          <ion-row class="ion-text-center">
            <ion-col size="auto">
              <ion-icon style="padding-top: 12px;" aria-hidden="true" name="home" size="large"></ion-icon>
            </ion-col>
            <ion-col>
              <h3><ion-text>Manage Address</ion-text></h3>
            </ion-col>
            <ion-col size="auto">
              <ion-button fill="clear"><ion-icon size="large" name="chevron-forward-circle-outline"></ion-icon></ion-button>
            </ion-col>
          </ion-row>
        </ion-grid>

        <ion-modal trigger="open-modal" (willDismiss)="onWillDismiss($event)">
          <ng-template>
            <ion-header>
              <ion-toolbar>
                <ion-buttons slot="start">
                  <ion-button (click)="cancel()">Cancel</ion-button>
                </ion-buttons>
                <ion-title>Edit</ion-title>
                <ion-buttons slot="end">
                  <ion-button (click)="confirm()" [strong]="true">Confirm</ion-button>
                </ion-buttons>
              </ion-toolbar>
            </ion-header>
            <ion-content class="ion-padding">
              <ion-item>
                <ion-label position="stacked">Enter your name</ion-label>
                <ion-input type="text" placeholder="Your name"[(ngModel)] = "userName"></ion-input>
                <ion-label position="stacked">Enter your email</ion-label>
                <ion-input type="text" placeholder="Your email"[(ngModel)] = "userEmail"></ion-input>
                <ion-label position="stacked">Enter your number</ion-label>
                <ion-input type="text" placeholder="Your number"[(ngModel)] = "userNumber"></ion-input>
              </ion-item>
            </ion-content>
          </ng-template>
        </ion-modal>

  <ion-card>
    <ion-card-header color="primary">
      <ion-card-title>Order History</ion-card-title>
    </ion-card-header>
   <br>
    <ion-card-content  *ngFor="let item of orderHistory">
      <ion-list class="orderHistory-card">
        <ion-item>
          <h2><ion-label>{{ item.restaurantName }} </ion-label></h2>
        </ion-item>
        <ion-item>
          <ion-label>Dish: {{ item.dishName }}</ion-label>
        </ion-item>
        <ion-item>
          <ion-label>Quantity: {{ item.quantity }}</ion-label>
        </ion-item>
      </ion-list>
    </ion-card-content>
    <ion-card-content>
      <ion-text color="primary">
        <h1>Total: {{ totalPrice | currency :'ZAR':'symbol'}}</h1>
      </ion-text>
      <ion-text color="secondary">
        <sub>Includes delivery fee</sub>
      </ion-text>
    </ion-card-content>
  </ion-card>

  <ion-grid>
    <ion-row>
      <ion-col>
        <ion-button style="width: 100%;" fill="outline" size="small" (click)="reOrderAddToCart()">Reorder All</ion-button>
      </ion-col>
      <ion-col>
        <ion-button style="width: 100%;" fill="outline" size="small"  id="open-help-modal" expand="block">Need Help?</ion-button>
      </ion-col>
    </ion-row>
  </ion-grid>

  <ion-modal #modal trigger="open-help-modal" [canDismiss]="canDismiss" [presentingElement]="page">
    <ng-template>
      <ion-header>
        <ion-toolbar>
          <ion-title>Modal</ion-title>
          <ion-buttons slot="end">
            <ion-button (click)="modal.dismiss()">Close</ion-button>
          </ion-buttons>
        </ion-toolbar>
      </ion-header>
      <ion-content class="ion-padding">
        <h1>
          Placing an order:
        </h1>
        <p>
          To place an order, simply search for the restaurant or cuisine you're interested in, browse their menu, and select the items you'd like to order. Once you're done, proceed to the checkout page and review your order details before submitting.
        </p>
        <h1>
          Making a payment:
        </h1>
        <p>
          We offer a variety of payment options, including credit/debit card, PayPal, and in-app wallet. Simply select your preferred payment method at checkout and follow the instructions to complete your transaction.
        </p>
        <h1>
          Changing delivery address:
        </h1>
        <p>
          If you need to change your delivery address after placing an order, please contact our support team as soon as possible. We'll do our best to accommodate your request, but please note that any changes made after the order has been dispatched may result in a delay or additional fee.
        </p>
        <h1>
          Changing user details:
        </h1>
        <p>
          To update your user details, including your name, email, phone number, or password, go to your account settings page and make the necessary changes. Please note that some details, such as your email or phone number, may be required for verification purposes and cannot be changed without additional steps.
        </p>
      </ion-content>
    </ng-template>
  </ion-modal>
</ion-content>
</div>



import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { Component } from '@angular/core';
import { ToastController } from '@ionic/angular';
import { HomePage } from '../home/home.page';

@Component({
  selector: 'app-cart',
  templateUrl: './cart.page.html',
  styleUrls: ['./cart.page.scss'],
  standalone: true,
  imports: [IonicModule, CommonModule, FormsModule],
  providers:[HomePage],
})
export class CartPage  {
  cartItems: any[] = [];
  deliveryInstructions: string = '';
  totalPrice: number = 0;
  itemPrice: number = 0;
  officeAddress: string = '123 Main St.';

  constructor(private toastController: ToastController, private homePage:HomePage) {}

 
  makePayment(){
  // Retrieve the orderList from local storage
  const orderList = JSON.parse(localStorage.getItem('orderList') ?? '[]');
  // Store the orderList in the paidList array
  localStorage.setItem('paidList', JSON.stringify(orderList));
  // Clear the orderList array in local storage
  localStorage.setItem('orderList', JSON.stringify([]));
    // Remove the order cards from the DOM after a short delay
    setTimeout(() => {
      const orderCards = document.querySelectorAll('.order-card');
      orderCards.forEach(card => card.remove());
    }, 100);
  };


  ionViewWillEnter() {
    // retrieve cart items from local storage
    const cartItems = JSON.parse(localStorage.getItem('orderList') ?? "[]");
    
    if (cartItems != null) {
      this.cartItems = cartItems;
      this.calculateTotalPrice();
    }
  }

  calculateTotalPrice() {
    let totalPrice = 0;
    let itemPrice = 0;

    console.log(this.cartItems);

      for (let item of this.cartItems) {
        itemPrice += item.dishPrice * item.quantity;
      }
      // add delivery fee to the total price
      totalPrice = itemPrice + 50;
      this.totalPrice = totalPrice;
      this.itemPrice = itemPrice;
      console.log(totalPrice)
    
    }

  async presentToast(position: 'middle') {
    const toast = await this.toastController.create({
      message: 'Payment Successful!',
      duration: 1500,
      position: position
    });
    await toast.present();
  }

  handlerMessage = '';

  public alertButtons = [
    {
      text: 'Cancel',
      role: 'cancel',
      handler: () => {  }
    },
    {
      text: 'OK',
      role: 'confirm',
      // I want to present a toast message when the user clicks OK 
      handler: () => {this.makePayment(); this.presentToast('middle'); this.ionViewWillEnter() }
    }
  ];

};

<ion-content [fullscreen]="true"  class="ion-padding">
  <ion-header>
    <ion-toolbar>
      <ion-title>Cart</ion-title>
    </ion-toolbar>
  </ion-header>

  <ion-card class="order-card" *ngFor="let item of cartItems">
    <ion-card-header color="primary">
      <ion-card-title>{{ item.restaurantName }}</ion-card-title>
    </ion-card-header>
    <br>
    <ion-card-content>
      <p>Dish: {{ item.dishName }}</p>
      <p>Quantity: {{ item.quantity }}</p>
      <p>Price: {{ item.dishPrice | currency :'ZAR':'symbol' }}</p>
    </ion-card-content>
  </ion-card>
  
  <ion-grid>
    <ion-row class="ion-text-center">
      <ion-col size="2">
        <ion-icon style="padding-top: 12px;" aria-hidden="true" name="home" size="large"></ion-icon>
      </ion-col>
      <ion-col style="padding-top: 13px;">
        <ion-row>
          Deliver to My Couch
        </ion-row>
        <ion-row>
          <ion-text color="medium"><sub>12 Main Street</sub></ion-text>
        </ion-row>
      </ion-col>
      <ion-col size="auto">
        <ion-button fill="clear"><ion-text color="danger" size="small">CHANGE</ion-text></ion-button>
      </ion-col>
    </ion-row>
  </ion-grid>

  <ion-card>
   
    <ion-card-header color="primary">
     <ion-card-title> Cart details </ion-card-title>
    </ion-card-header>
  
    <ion-card-content>
      <ion-grid>
        <ion-row>
          <ion-col>Item Total:</ion-col>
          <ion-col>{{itemPrice | currency :'ZAR':'symbol'}}</ion-col>
        </ion-row>
        <ion-row>
          <ion-col>Delivery Fee:</ion-col>
          <ion-col>{{ 50 | currency :'ZAR':'symbol'}}</ion-col>
        </ion-row>
        <ion-row>
          <ion-col>Total Price:</ion-col>
          <ion-col>{{ totalPrice | currency :'ZAR':'symbol'}}</ion-col>
        </ion-row>
      </ion-grid> 
      
      <ion-button id="present-alert" expand="block" color="primary">Make Payment</ion-button> 
      <ion-toast class="custom-toast" position="middle" trigger="open-toast" message="Payment successful!" [duration]="3000" icon="checkmark-sharp"></ion-toast>
    </ion-card-content>
  </ion-card>


  <ion-alert
    trigger="present-alert"
    header="Confirm Payment"
    [buttons]="alertButtons"
  ></ion-alert>

</ion-content> 


<ion-content [fullscreen]="true"  class="ion-padding">
  <ion-header>
    <ion-toolbar>
      <ion-title>Cart</ion-title>
    </ion-toolbar>
  </ion-header>

  <ion-card class="order-card" *ngFor="let item of cartItems">
    <ion-card-header color="primary">
      <ion-card-title>{{ item.restaurantName }}</ion-card-title>
    </ion-card-header>
    <br>
    <ion-card-content>
      <p>Dish: {{ item.dishName }}</p>
      <p>Quantity: {{ item.quantity }}</p>
      <p>Price: {{ item.dishPrice | currency :'ZAR':'symbol' }}</p>
    </ion-card-content>
  </ion-card>
  
  <ion-grid>
    <ion-row class="ion-text-center">
      <ion-col size="2">
        <ion-icon style="padding-top: 12px;" aria-hidden="true" name="home" size="large"></ion-icon>
      </ion-col>
      <ion-col style="padding-top: 13px;">
        <ion-row>
          Deliver to My Couch
        </ion-row>
        <ion-row>
          <ion-text color="medium"><sub>12 Main Street</sub></ion-text>
        </ion-row>
      </ion-col>
      <ion-col size="auto">
        <ion-button fill="clear"><ion-text color="danger" size="small">CHANGE</ion-text></ion-button>
      </ion-col>
    </ion-row>
  </ion-grid>

  <ion-card>
   
    <ion-card-header color="primary">
     <ion-card-title> Cart details </ion-card-title>
    </ion-card-header>
  
    <ion-card-content>
      <ion-grid>
        <ion-row>
          <ion-col>Item Total:</ion-col>
          <ion-col>{{itemPrice | currency :'ZAR':'symbol'}}</ion-col>
        </ion-row>
        <ion-row>
          <ion-col>Delivery Fee:</ion-col>
          <ion-col>{{ 50 | currency :'ZAR':'symbol'}}</ion-col>
        </ion-row>
        <ion-row>
          <ion-col>Total Price:</ion-col>
          <ion-col>{{ totalPrice | currency :'ZAR':'symbol'}}</ion-col>
        </ion-row>
      </ion-grid> 
      
      <ion-button id="present-alert" expand="block" color="primary">Make Payment</ion-button> 
      <ion-toast class="custom-toast" position="middle" trigger="open-toast" message="Payment successful!" [duration]="3000" icon="checkmark-sharp"></ion-toast>
    </ion-card-content>
  </ion-card>


  <ion-alert
    trigger="present-alert"
    header="Confirm Payment"
    [buttons]="alertButtons"
  ></ion-alert>

</ion-content> 


import { Component } from '@angular/core';
import { IonicModule } from '@ionic/angular';
import { CommonModule } from '@angular/common';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
  standalone: true,
  imports: [IonicModule, CommonModule],
})
export class HomePage {
 
  restaurantList = [
    {
      name: "KFC",
      dish: "KFC Bucket",
      rating: 3.9,
      distance: "4km",
      price: 54.90,
      image: "assets/KFC.png",
      topDish: "Fast Food",
      orderQuantity: 0,
    },
    {
      name: "Burger King",
      dish: "Whopper",
      rating: 3.7,
      distance: "6.7km",
      price: 59.95,
      image: "assets/BK.png",
      topDish: "Fast Food",
      orderQuantity: 0,
    },
    {
      name: "Pizza Hut",
      dish: "My Box",
      rating: 4.0,
      distance: "7.1km",
      price: 44.90,
      image: "assets/PH.png",
      topDish: "Fast Food",
      orderQuantity: 0,
    },
    {
      name: "McDonalds",
      dish: "Big Mac",
      rating: 4.3,
      distance: "3.2km",
      price: 49.90,
      image: "assets/Mac.png",
      topDish: "Fast Food",
      orderQuantity: 0,
    },
  ];
  

  addToCart(restaurant: { 
    name: string, 
    dish: string, 
    rating: number, 
    distance: string, 
    price: number, 
    topDish: string, 
    orderQuantity: number }) {
    
    const orderList = JSON.parse(localStorage.getItem('orderList')??'[]');
    const orderIndex = orderList.findIndex((order: {restaurantName:string;})=> order.restaurantName === restaurant.name );

    if (orderIndex === -1) {
      orderList.push({
        dishPrice: restaurant.price,
        restaurantName: restaurant.name,
        dishName: restaurant.dish,
        quantity: 1,
      });
    } else {
      orderList[orderIndex].quantity++;
    }
    localStorage.setItem('orderList', JSON.stringify(orderList));
  }

  reOrderAddToCart(restaurant: { 
    name: string, 
    dish: string, 
    rating: number, 
    distance: string, 
    price: number, 
    topDish: string, 
    orderQuantity: number }) {
    
    const paidorderList = JSON.parse(localStorage.getItem('paidList')??'[]');
    console.log(paidorderList)

    const orderIndex = paidorderList.findIndex((order: {name:string;})=> order.name === restaurant.name );
    console.log(orderIndex)

    if (orderIndex === -1) {
      paidorderList.push({
        dishPrice: restaurant.price,
        restaurantName: restaurant.name,
        dishName: restaurant.dish,
        quantity: 1,
      });
    } else {
      paidorderList[orderIndex].quantity++;
    }
    localStorage.setItem('orderList', JSON.stringify(paidorderList));
  }

  
}
<ion-header [translucent]="true">
  <ion-toolbar>
    <ion-title>
      Home
    </ion-title>
  </ion-toolbar>
</ion-header>


<ion-content [fullscreen]="true">
  <!-- ------------------ -->
  <ion-searchbar (ionInput)="search($event)" animated="true" placeholder="Search"></ion-searchbar>
      <ion-list  *ngFor="let data of restaurantList">
        <ion-item lines="none" color="light">
          <ion-thumbnail slot="start">
            <img alt="Silhouette of mountains" src={{data.image}}/>
          </ion-thumbnail>
          <ion-grid>
            <ion-row>
              <ion-col>
                <ion-text>
                  {{data.name}}
                </ion-text>
              </ion-col>
            </ion-row>

            <ion-row>
              <ion-col>
                <ion-text color="medium">
                  {{data.type}}
                </ion-text>
              </ion-col>
            </ion-row>

            <ion-row>
              <ion-col>
                <ion-icon name="star"></ion-icon> {{data.rating}}
              </ion-col>
              <ion-col>
                R{{data.price}}
              </ion-col>
            </ion-row>

            <ion-row>
              <ion-col>
                <ion-icon name="car"></ion-icon> <ion-text color="danger"> {{data.distance}}</ion-text>
              </ion-col>
            </ion-row>
            <ion-row>
              <ion-button style="width: 100%">Add to cart</ion-button> 
            </ion-row>
          </ion-grid>
        </ion-item>
      </ion-list>
</ion-content>
<ion-header [translucent]="true">
  <ion-toolbar>
    <ion-title>
      Home
    </ion-title>
  </ion-toolbar>
</ion-header>


<ion-content [fullscreen]="true">
  <!-- ------------------ -->
  <ion-searchbar (ionInput)="search($event)" animated="true" placeholder="Search"></ion-searchbar>
      <ion-list  *ngFor="let data of restaurantList">
        <ion-item lines="none" color="light">
          <ion-thumbnail slot="start">
            <img alt="Silhouette of mountains" src={{data.image}}/>
          </ion-thumbnail>
          <ion-grid>
            <ion-row>
              <ion-col>
                <ion-text>
                  {{data.name}}
                </ion-text>
              </ion-col>
            </ion-row>

            <ion-row>
              <ion-col>
                <ion-text color="medium">
                  {{data.type}}
                </ion-text>
              </ion-col>
            </ion-row>

            <ion-row>
              <ion-col>
                <ion-icon name="star"></ion-icon> {{data.rating}}
              </ion-col>
              <ion-col>
                R{{data.price}}
              </ion-col>
            </ion-row>

            <ion-row>
              <ion-col>
                <ion-icon name="car"></ion-icon> <ion-text color="danger"> {{data.distance}}</ion-text>
              </ion-col>
            </ion-row>
            <ion-row>
              <ion-button style="width: 100%">Add to cart</ion-button> 
            </ion-row>
          </ion-grid>
        </ion-item>
      </ion-list>
</ion-content>
import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
import { IonicModule } from '@ionic/angular';
import { HomePage } from '../home/home.page';

interface Restaurant {
  name: string;
  dish: string;
  rating: number;
  distance: string;
  price: number;
  image: string;
  topDish: string;
}

@Component({
  selector: 'app-search',
  templateUrl: './search.page.html',
  styleUrls: ['./search.page.scss'],
  standalone: true,
  imports: [IonicModule, CommonModule, FormsModule],
  providers:[HomePage]
})
export class SearchPage implements OnInit {
  searchTerm!: '';
  searchResults: Restaurant[] = [];

  ngOnInit() {
  }

  constructor( private homePage: HomePage) { }
  // Filters the restaurant list based on the user's search term for name, dish, rating, and distance.
  searchRestaurants() {
    if (this.searchTerm.length > 0) {
      this.searchResults = this.homePage.restaurantList.filter((restaurant) =>
        restaurant.name.toLowerCase().includes(this.searchTerm.toLowerCase()) ||
        restaurant.dish.toLowerCase().includes(this.searchTerm.toLowerCase()) ||
        restaurant.topDish.toLowerCase().includes(this.searchTerm.toLowerCase()) ||
        (restaurant.rating >= parseInt(this.searchTerm) && restaurant.rating < parseInt(this.searchTerm) + 1)

      )
    } else {
      this.searchResults = [];
    };
  };


  addToCart(restaurant:any){
    this.homePage.addToCart(restaurant);
  }

}
<template>
  <div>
    <vxe-toolbar>
      <template #buttons>
        <vxe-button @click="allAlign = 'left'">居左</vxe-button>
        <vxe-button @click="allAlign = 'center'">居中</vxe-button>
        <vxe-button @click="allAlign = 'right'">居右</vxe-button>
      </template>
    </vxe-toolbar>

    <vxe-table
      :align="allAlign"
      :data="tableData">
      <vxe-column type="seq" width="60"></vxe-column>
      <vxe-column field="name" title="Name"></vxe-column>
      <vxe-column field="sex" title="Sex"></vxe-column>
      <vxe-column field="age" title="Age"></vxe-column>
    </vxe-table>
  </div>
</template>

<script lang="ts" setup>
import { ref } from 'vue'
import { VxeTablePropTypes } from 'vxe-table'

interface RowVO {
  id: number
  name: string
  role: string
  sex: string
  age: number
  address: string
}

const allAlign = ref<VxeTablePropTypes.Align>(null)

const tableData = ref<RowVO[]>([
  { id: 10001, name: 'Test1', role: 'Develop', sex: 'Man', age: 28, address: 'test abc' },
  { id: 10002, name: 'Test2', role: 'Test', sex: 'Women', age: 22, address: 'Guangzhou' },
  { id: 10003, name: 'Test3', role: 'PM', sex: 'Man', age: 32, address: 'Shanghai' },
  { id: 10004, name: 'Test4', role: 'Designer', sex: 'Women', age: 24, address: 'Shanghai' }
])
</script>
# Installing Rosetta
/usr/sbin/softwareupdate --install-rosetta --agree-to-license

# Install NVM
# https://github.com/nvm-sh/nvm#install--update-script
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash

# Installing Node 14 by NVM
arch
# >>> arm64
arch -x86_64 zsh
arch
# >>> i386
nvm install 14
nvm use 14
<button
   className="modal-close-button"
   onClick={handleCloseModal}
 >
   <span aria-hidden="true">&times;</span>
 </button>
 
 You are a CSS expert
 
 I want you to do following changes in styling.
 
 1. Rounded shape. Apply border radius to 50pc.
 2. Background to "#f1f1f1".
 3. No outer border color.
 3. border of child element span should be 2px solid #494A53.
dataSrc: function (json) {
  json.draw = json.jsonData.draw;
  json.recordsTotal = json.jsonData.Total_Records;
  json.recordsFiltered = json.jsonData.Total_Records;
  // json.data.data = response.jsonData.CR_list;
  //Make your callback here.
  // alert("Done!");
  // console.log(json);
  return json.jsonData.CR_list;
},
.initials-avatar {
    background-color: #023979;
    border-radius: 50%;
    display: flex;
    justify-content: center;
    align-items: center;
    padding: 5px;
    width: 38px;
    height: 38px;
}
/* eslint-disable @typescript-eslint/no-explicit-any */
import { Request, Response } from 'express'
import createHttpError from 'http-errors'
import { z, ZodError, ZodIssue } from 'zod'

export interface CreateHandler<
  Params extends z.ZodTypeAny = any,
  Body extends z.ZodTypeAny = any,
  Query extends z.ZodTypeAny = any,
  ResJson extends z.ZodTypeAny = any,
  OmittedFields extends 'params' | 'body' | 'query' | '' = '',
> {
  (): {
    resolve(
      f: (
        req: Request<z.input<Params>, any, z.input<Body>>,
        res: Response<ResJson>,
      ) => any,
    ): (req: Request, res: Response) => void
    inputParams<T extends z.ZodTypeAny>(
      paramsSchema: T,
    ): Omit<
      ReturnType<
        CreateHandler<T, Body, Query, ResJson, OmittedFields | 'params'>
      >,
      OmittedFields | 'params'
    >
    inputBody<T extends z.ZodTypeAny>(
      bodySchema: T,
    ): Omit<
      ReturnType<
        CreateHandler<Params, T, Query, ResJson, OmittedFields | 'body'>
      >,
      OmittedFields | 'body'
    >
    inputQuery<T extends z.ZodTypeAny>(
      querySchema: T,
    ): Omit<
      ReturnType<
        CreateHandler<Params, Body, T, ResJson, OmittedFields | 'body'>
      >,
      OmittedFields | 'query'
    >
    responseJson<T extends z.ZodTypeAny>(
      resJsonSchema: T,
    ): Omit<
      ReturnType<
        CreateHandler<Params, Body, Query, z.input<T>, OmittedFields | 'body'>
      >,
      OmittedFields | 'query'
    >
  }
}

type HandlerThis = {
  paramsSchema: z.ZodAny
  bodySchema: z.ZodAny
  querySchema: z.ZodAny
  resJsonSchema: z.ZodAny
}

const formatZodError = {
  all: (prefix: string, zodError: ZodError) =>
    Object.values(
      zodError.flatten(
        (issue: ZodIssue) => `[${prefix}${issue.path}]: ${issue.message}`,
      ).fieldErrors,
    ).join(', '),
  first: (prefix: string, zodError: ZodError) =>
    Object.values(
      zodError.flatten(
        (issue: ZodIssue) => `[${prefix}${issue.path}]: ${issue.message}`,
      ).fieldErrors,
    )[0],
}

export const createHandler: CreateHandler = function () {
  return {
    inputParams(paramsSchema) {
      ;(<any>this).paramsSchema = paramsSchema
      return this
    },
    inputBody(bodySchema) {
      ;(<any>this).bodySchema = bodySchema
      return this
    },
    inputQuery(querySchema) {
      ;(<any>this).querySchema = querySchema
      return this
    },
    responseJson(resJsonSchema) {
      ;(<any>this).resJsonSchema = resJsonSchema
      return this
    },
    resolve(this: HandlerThis, f) {
      return async (req, res) => {
        if (this.paramsSchema) {
          const paramsValidationResult = this.paramsSchema.safeParse(req.params)
          if (!paramsValidationResult.success) {
            return res
              .status(400)
              .json(formatZodError.all('param.', paramsValidationResult.error))
          }

          req.params = paramsValidationResult.data
        }

        if (this.bodySchema) {
          const bodyValidationResult = this.bodySchema.safeParse(req.body)
          if (!bodyValidationResult.success) {
            return res
              .status(400)
              .json(formatZodError.all('body.', bodyValidationResult.error))
          }

          req.body = bodyValidationResult.data
        }

        if (this.querySchema) {
          const queryValidationResult = this.querySchema.safeParse(req.query)
          if (!queryValidationResult.success) {
            return res
              .status(400)
              .json(formatZodError.all('query.', queryValidationResult.error))
          }

          req.query = queryValidationResult.data
        }

        // Because express is very old and can't handle async exceptions, let's do it from this helper
        const resJson: any = res.json
        try {
          if (this.resJsonSchema) {
            const newRes: any = Object.assign(res, { json: undefined })
            newRes.json = (json: any) => {
              const resJsonValidationResult = this.resJsonSchema.safeParse(json)
              if (!resJsonValidationResult.success) {
                res.status(400)
                resJson.call(
                  res,
                  formatZodError.all('resJson.', resJsonValidationResult.error),
                )
                return
              }
              resJson.call(res, json)
            }
            await f(req, newRes as any)
            return
          }

          await f(req, res)
          return
        } catch (error) {
          if (createHttpError.isHttpError(error)) {
            res.status(error.status)
            resJson.call(res, { message: error.message })
          }
          return
        }
      }
    },
  }
}
npm create vite@latest name-of-project -- --template react-ts
import { BrowserRouter, Routes, Route } from 'react-router-dom';
import Login from './Login';
import Home from './Home';

...


return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Login/>} exact />
        <Route path="/home" element={<Home/>} exact />
      </Routes>
    </BrowserRouter>
  );
import React from 'react';
import logo from './logo.svg';

function Home() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Welcome to the home page!
        </p>
      </header>
    </div>
  );
}

export default Home;
import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';

function Login(props) {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');
  const navigate = useNavigate();

  function handleUsernameChange(event) {
    setUsername(event.target.value);
  }

  function handlePasswordChange(event) {
    setPassword(event.target.value);
  }

  function handleSubmit(event) {
    event.preventDefault();

    // Here you can add your login authentication logic
    if (username === 'user' && password === 'password') {
      // If the login is successful, redirect to the home page
        navigate("/home")
    } else {
      // If the login fails, display an error message
      setError('Invalid username or password');
    }
  }

  return (
    <div className="App">
      <div>
      {error && <p>{error}</p>}
      <h1>Login</h1>
      <form onSubmit={handleSubmit}>
        <label>
          Username:
          <input type="text" value={username} onChange={handleUsernameChange} required />
        </label>
        <br />
        <label>
          Password:
          <input type="password" value={password} onChange={handlePasswordChange} required />
        </label>
        <br />
        <button type="submit">Submit</button>
      </form>
      </div>
    </div>
  );
}

export default Login;
export interface ICallFn {
  resolve: (value: unknown) => void;
  reject: (reason?: unknown) => void;
  fnToCall: (...args: any[]) => Promise<any>;
  args: any[];
}

export default class Semaphore {
  currentRequests: ICallFn[];
  runningRequests: number;
  maxConcurrentRequests: number;
  /**
   * Creates a semaphore that limits the number of concurrent Promises being handled
   * @param {*} maxConcurrentRequests max number of concurrent promises being handled at any time
   */
  constructor(maxConcurrentRequests = 1) {
    this.currentRequests = [];
    this.runningRequests = 0;
    this.maxConcurrentRequests = maxConcurrentRequests;
  }

  /**
   * Returns a Promise that will eventually return the result of the function passed in
   * Use this to limit the number of concurrent function executions
   * @param {*} fnToCall function that has a cap on the number of concurrent executions
   * @param  {...any} args any arguments to be passed to fnToCall
   * @returns Promise that will resolve with the resolved value as if the function passed in was directly called
   */
  callFunction(fnToCall, ...args) {
    return new Promise((resolve, reject) => {
      this.currentRequests.push({
        resolve,
        reject,
        fnToCall,
        args
      });
      this.tryNext();
    });
  }

  tryNext() {
    if (!this.currentRequests.length) {
      return;
    }
    if (this.runningRequests < this.maxConcurrentRequests) {
      const { resolve, reject, fnToCall, args } = this.currentRequests.shift();
      this.runningRequests++;
      fnToCall(...args)
        .then((res) => resolve(res))
        .catch((err) => reject(err))
        .finally(() => {
          this.runningRequests--;
          this.tryNext();
        });
    }
  }
}
import * as borsh from 'borsh';
import * as web3 from "@solana/web3.js";
import * as BufferLayout from "@solana/buffer-layout";
//const BN = require("bn.js");
import {Buffer} from "buffer";
/**
 * The public key of the account we are saying hello to
 */
 let greetedPubkey: web3.PublicKey;
 /**
 * The state of a greeting account managed by the hello world program
 */
class GreetingAccount {
    counter = 0;
    constructor(fields: {counter: number} | undefined = undefined) {
      if (fields) {
        this.counter = fields.counter;
      }
    }
  }

const GreetingSchema = new Map([
    [GreetingAccount, {kind: 'struct', fields: [['counter', 'u32']]}],
  ]);

  const GREETING_SIZE = borsh.serialize(
    GreetingSchema,
    new GreetingAccount(),
  ).length;

const connection = new web3.Connection(web3.clusterApiUrl("devnet"));

async function main(){
    //pays for the transaction (message)
     const key: Uint8Array = Uint8Array.from([PRIVATE KEY DEL QUE PAGA]);
     /*const data_to_send: Buffer = Buffer.from(
            Uint8Array.of(0, ...new BN(10).toArray("le", 8)
            ));

             const data_b = borsh.serialize(
              GreetingSchema,
              new GreetingAccount(),
              
            )*/

    const layout = BufferLayout.struct([BufferLayout.u32("counter")])
    let data: Buffer = Buffer.alloc(layout.span);
    layout.encode({counter:3}, data);

    const signer: web3.Keypair = web3.Keypair.fromSecretKey(key);
    let programId: web3.PublicKey = new web3.PublicKey("PROGRAM-ID");
    
    const GREETING_SEED = 'hello 42';
    
    greetedPubkey = await web3.PublicKey.createWithSeed(
      signer.publicKey,
      GREETING_SEED,
      programId,
    );
    console.log(greetedPubkey.toBase58(), 'has been grenerated');
    
    //greetedPubkey = new web3.PublicKey("HV32BHyveh4joMrhkSfmsbTBEMZbJ8qoJg4zWJz5eTAP");

    let fees = 0;
    const lamports = await connection.getMinimumBalanceForRentExemption(
        GREETING_SIZE,
    );
//This creteAccount with Seed  only first time    
    const transaction = new web3.Transaction()
    .add(
     web3.SystemProgram.createAccountWithSeed({
       fromPubkey: signer.publicKey,
       basePubkey: signer.publicKey,
       seed: GREETING_SEED,
       newAccountPubkey: greetedPubkey,
       lamports,
       space: GREETING_SIZE,
       programId,
     }),
   );
    transaction.add(
        new web3.TransactionInstruction({
            keys: [
            {pubkey: greetedPubkey, isSigner: false, isWritable: true}],
            programId,
            data: data
        })
    );

    await web3.sendAndConfirmTransaction(connection, transaction, [signer])
        .then((sig)=> {
            console.log("sig: {}", sig);
        });
    reportGreetings();
    }

    async function reportGreetings(): Promise<void> {
        const accountInfo = await connection.getAccountInfo(greetedPubkey);
        if (accountInfo === null) {
          throw 'Error: cannot find the greeted account';
        }
        const greeting = borsh.deserialize(
          GreetingSchema,
          GreetingAccount,
          accountInfo.data,
        );
        console.log(greetedPubkey.toBase58(),
            'has been greeted',
            Number(greeting.counter),
            'time(s)',
        );
    }

    main();
use borsh::{BorshDeserialize, BorshSerialize};
use solana_program::{
    account_info::{next_account_info, AccountInfo},
    entrypoint,
    entrypoint::ProgramResult,
    msg,
    program_error::ProgramError,
    pubkey::Pubkey,
};

/// Define the type of state stored in accounts
#[derive(BorshSerialize, BorshDeserialize, Debug)]
pub struct GreetingAccount {
    pub counter: u32,
}

entrypoint!(process_instruction);

pub fn process_instruction(
    program_id: &Pubkey, // Public key of the account the hello world program was loaded into
    accounts: &[AccountInfo], // The account to say hello to
    _instruction_data: &[u8], // Ignored, all helloworld instructions are hellos
) -> ProgramResult {

    let accounts_iter = &mut accounts.iter();
    let account = next_account_info(accounts_iter)?;
    
    msg!("Start instruction decode");
    let data_received = GreetingAccount::try_from_slice(_instruction_data).map_err(|err| {
      msg!("Receiving counter u32, {:?}", err);
      ProgramError::InvalidInstructionData  
    })?;
    msg!("Greeting passed to program is {:?}", data_received);
    msg!("Count: {}!", data_received.counter);

   // The account must be owned by the program in order to modify its data
    if account.owner != program_id {
        msg!("Wrong permissions. Greeted account does not have the correct program id");
        return Err(ProgramError::IncorrectProgramId);
    }

    let mut greeting_account = GreetingAccount::try_from_slice(&account.data.borrow())?;
    greeting_account.counter += data_received.counter;
    greeting_account.serialize(&mut &mut account.data.borrow_mut()[..])?;

    msg!("Greeted {} time(s)!", greeting_account.counter);

    Ok(())
}
[package]
name = "send_save_serial_data_program"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
    solana-program = "=1.10.2"
    borsh = "0.9.3"
    borsh-derive = "0.9.1"


[lib]
    crate-type = ["cdylib", "lib"]
import * as web3 from "@solana/web3.js";
const BN = require ("bn.js");
const connection = new web3.Connection(web3.clusterApiUrl("devnet"));

async function main() {
    const key: Uint8Array = Uint8Array.from([PRIVATE KEY del que paga]);
    const signer: web3.Keypair = web3.Keypair.fromSecretKey(key);

    let programId: web3.PublicKey = new web3.PublicKey("Tu ProgramId");
    const data: Buffer = Buffer.from(
        Uint8Array.of(0, ...new BN(VALOR ENTERO DE 8 BITS).toArray("le",8))
    );

    let transaction: web3.Transaction = new web3.Transaction();
    transaction.add(
        new web3.TransactionInstruction({
            keys: [],
            programId,
            data
        })
    );
    await web3.sendAndConfirmTransaction(
        connection, transaction, [signer])
        .then((sig) => {
            console.log("signature:{}",sig);
        });
}

main()
import * as web3 from "@solana/web3.js";

const connection = new web3.Connection(web3.clusterApiUrl("devnet"));

async function main(){
    const key: Uint8Array = Uint8Array.from([PRIVATE KEY del que paga]);
    const signer = web3.Keypair.fromSecretKey(key);
    let programId: web3.PublicKey = new web3.PublicKey("Tu ProgramId");

    let transaction = new web3.Transaction();

    transaction.add (
        new web3.TransactionInstruction({
            keys: [],
            programId,
            data: Buffer.alloc(0)
        })
    )

    await web3
        .sendAndConfirmTransaction(connection, transaction, [signer])
        .then((sig)=> {
            console.log("sig: {}", sig);
        });

}

main();
  static userTimezoneToSpecifiedTimeZone(date: Date, time: string, timeZone: string): Date {
    // Major timeZone's for Australia and their offset values in hours
    // NOTE Darwin etc -> I'm not sure 9.5 or 10.5 will work
    const DST_OFFSETS = {
      'Australia/Sydney': [11, 10],
      'Australia/Brisbane': [11, 10],
      'Australia/Melbourne': [11, 10],
      'Australia/Canberra': [11, 10],
      'Australia/Darwin': [10.5, 9.5],
      'Australia/Adelaide': [10.5, 9.5],
      'Australia/BrokenHill': [10.5, 9.5],
      'Australia/Perth': [9, 8]
    };

    // Calculate the offset depending on if the date is in is DST or not
    const [dstStartOffset, dstEndOffset] = DST_OFFSETS[timeZone];
    const daylightSavingOffset = this.isDaylightSavingTime(date, timeZone) ? dstStartOffset : dstEndOffset;

    const hoursAndMinutes = time.split(':');

    // Collect raw values to create date object
    let year = date.getFullYear();
    let month = date.getMonth();
    let day = date.getDate();
    let hours = Number(hoursAndMinutes[0]);
    const minutes = Number(hoursAndMinutes[1]);

    // We then convert these values to the timezone's UTC by adding the offset
    // i.e. Sydney is 10/11 hours ahead of GMT, so we need to minus 10/11 hours to get GMT.
    // allow for the GMT being the day, month and year before when subtracting the offset.
    if ((hours - daylightSavingOffset) < 0) {
      hours = 24 + (hours - daylightSavingOffset);
      day--;
      if ((month - 1) < 0) {
        year  = year--;
        month = 11;
      }
    } else {
      hours = hours - daylightSavingOffset;
    }
    
    // Create the date object using the UTC value we created above.
    const returnDate = new Date(Date.UTC(year, month, day, hours, minutes, 0));

    // console.log(`${timeZone} Timezone from FormHelper-> ` + returnDate.toLocaleString(undefined, {timeZone: timeZone}))

    return returnDate;
    
   }

   static isDaylightSavingTime(date: Date, timeZone: string): boolean {
    // Get the time zone offset for the specified date
    const offset = new Date(date.toLocaleString('en-US', { timeZone })).getTimezoneOffset();
  
    // Calculate the daylight saving time start and end dates for the current year
    const year = date.getFullYear();
    const dstStart = new Date(Date.UTC(year, 9, 1, 16)).toLocaleString('en-US', { timeZone });
    const dstEnd = new Date(Date.UTC(year, 3, 1, 16)).toLocaleString('en-US', { timeZone });
  
    // Determine if the specified date falls within the daylight saving time period
    return offset < new Date(dstEnd).getTimezoneOffset() && offset >= new Date(dstStart).getTimezoneOffset();
  }
  
export abstract class DumbComponent {

   private readonly subClassConstructor: Function;

   protected constructor() {
      this.subClassConstructor = this.constructor;

      if (this.isEmptyConstructor() || arguments.length !== 0) {
         this.throwError('it should not inject services');
      }
   }

   private isEmptyConstructor(): boolean {
      return this.subClassConstructor.toString().split('(')[1][0] !== ')';
   }

   private throwError(reason: string): void {
      throw new Error(`Component "${this.subClassConstructor.name}" is a DumbComponent, ${reason}.`);
   }
}
import { PrismaClient } from "@prisma/client";

declare global {
  namespace NodeJS {
    interface Global {}
  }
}
// add prisma to the NodeJS global type
interface CustomNodeJsGlobal extends NodeJS.Global {
  prisma: PrismaClient;
}

// Prevent multiple instances of Prisma Client in development
declare const global: CustomNodeJsGlobal;

const prisma = global.prisma || new PrismaClient();

if (process.env.NODE_ENV === "development") global.prisma = prisma;

export default prisma;
npm install typescript --save-dev
npm install @types/node --save-dev
npx tsc --init --rootDir src --outDir lib --esModuleInterop --resolveJsonModule --lib es6,dom --module commonjs
import { Predicate } from '@nolawnchairs/utils'

export namespace Arrays {

  /**
   * Partitions an array into multiple arrays. A single provided predicate
   * will yield two partitions, where the first (0th) array contains items where
   * the predicate returned true, the second with the items where the predicate
   * returned false. If multiple predicates are provided, each nth partition
   * returned will contain a partition of the array whereby the nth
   * predicate returned true
   *
   * @export
   * @template T
   * @param {T[]} array
   * @param {Predicate<T>[]} predicates
   * @return {*}  {T[][]}
   */
  export function partition<T>(array: T[], ...predicates: Predicate<T>[]): T[][] {
    if (predicates.length === 1)
      return array.reduce((acc, item) => predicates[0](item)
        ? (acc[0].push(item), acc)
        : (acc[1].push(item), acc), [[], []])
    return predicates.reduce((acc, partitioner) => {
      return [...acc, array.filter(partitioner)]
    }, [])
  }
}

 const tabsInAssets = ['Coupe', 'Graph']
 const [tabSelectedIndex, setTabSelectedIndex] = useState<number>(0)

    
// html:    
      { tabsInAssets.map((elem, index) =>
                                    <button key={index} 
                                    className={tabSelectedIndex === index ?
                                        'bg-gray-400 mr-2 w-12 rounded font-Inter font-medium': 
                                        'bg-gray-200 mr-2 w-12 rounded font-Inter font-medium'} 
                                        onClick={() => {setTabSelectedIndex(index) }}>{elem}</button>
                                )}
                                
import { NextApiRequest, NextApiResponse } from "next";
import { Configuration, OpenAIApi } from "openai";
import Message from "./models/messages";

const configuration = new Configuration({
  apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);

function generatePrompt(message: string) {
  return `The following is a conversation with an AI assistant. The assistant is helpful, creative, clever, loving, intelligent and very friendly.
    
  
  Human: ${message} 
  AI: ` ;
}

const response = async (req: NextApiRequest, res: NextApiResponse) => {
  try {

    const completion = await openai.createCompletion({
      model: "text-davinci-002",
      prompt: generatePrompt(req.body.messageBody),
      temperature: 0.9,
      max_tokens: 150,
      top_p: 1,
      frequency_penalty: 0.0,
      presence_penalty: 0.6,
      stop: [" Human:", " AI:"],
    });
const result= completion.data.choices[0].text 



    const message = await Message.create({ messageBody: result, label: "AI"});
    res.status(200).json(message);
    res.end()
  } catch (error) {
    res.json(error);
  }
};
export default response;
import { NextApiRequest, NextApiResponse } from "next";
import Message from "../models/messages";


}
export const config = {
  api: {
      externalResolver: true
  }
}

export const createMessage = async (
  req: NextApiRequest,
  res: NextApiResponse
) => {

  const { messageBody } = req.body;
  try {


    const message = await Message.create({ messageBody, label: "Human" });
    res.status(200).json(message);
    res.end()
  } catch (error) {
    res.status(500).json(error);
  }
};


export const getMessages=async(  req: NextApiRequest,
    res: NextApiResponse)=>{
   
try {

    const messages= await Message.find({})
    res.status(200).json(messages);
    res.end()
} catch (error) {
    res.json(error)
}
}
import { NextApiRequest, NextApiResponse } from "next";
import dbConnect from "../config/dbConfig";
import { createMessage, getMessages } from "../controllers/messages";

export default async function hundler(req: NextApiRequest, res: NextApiResponse) {
const {method}=req
switch (method) {
    case "GET":
        await dbConnect()
        getMessages(req, res)
        break;
    case "POST": 
    await dbConnect()
    createMessage(req, res)
    break;
}

}
import { Model, model, models, Schema, Types } from "mongoose";

export interface MessageType {
    messageBody: string,
    creator: Types.ObjectId
    id: string
    _id: Types.ObjectId
  label: "AI" | "Human"
}
const messageSchema= new Schema({
    messageBody: String,
    creator: {
        type: Types.ObjectId,
        ref: "User"
    },
  label: String

    },
    {
        timestamps: true,
        toJSON: {
            virtuals: true,
        },
        toObject: {
            virtuals: true,
        },
    }
    
)
const Message= (models.Message || model("Message", messageSchema)) as Model<MessageType>;
export default Message;
import mongoose from "mongoose";

const dbConnect = async () => {
    try {
        await mongoose.connect(process.env.MONGO_URL!);
        console.log("DB successfully connected");
    } catch (error) {
        console.log(error);
    }
};

export default dbConnect;
import { NextApiRequest, NextApiResponse } from "next";
import { Configuration, OpenAIApi } from "openai";


const configuration = new Configuration({
  apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);

function generatePrompt(message: string) {
  return `The following is a conversation with an AI assistant. The assistant is helpful, creative, clever, and very friendly.
  
  Human: Hello, who are you? 
  AI: I'm good, thank you. How are you and how may  I help you today? 
    
  
  Human: ${message} 
  AI: ` ;
}

const response = async (req: NextApiRequest, res: NextApiResponse) => {
  try {

    const completion = await openai.createCompletion({
      model: "text-davinci-002",
      prompt: generatePrompt(req.body.messageBody),
      temperature: 0.9,
      max_tokens: 150,
      top_p: 1,
      frequency_penalty: 0.0,
      presence_penalty: 0.6,
      stop: [" Human:", " AI:"],
    });
const result= completion.data.choices[0].text 


    res.status(200).json(result);
    res.end()
  } catch (error) {
    res.json(error);
  }
};
export default response;
import { CropperObj, IImageCropperResult } from '@eduswiper/types';
import { expose } from 'threads/worker';

expose(function onExportCanvas(
	cropperObj: CropperObj
): Promise<IImageCropperResult> {
	return new Promise((resolve) => {
		const imageData = cropperObj.cropper.getImageData();
		const canvasData = cropperObj.cropper.getCanvasData();
		const canvas = cropperObj.cropper.getCroppedCanvas();
		const editedURL = canvas.toDataURL();

		resolve({ canvasData, imageData, editedURL });
	});
});
import { Injectable } from '@angular/core';
import { CropperObj, IDataToCrop, IImageCropperResult } from '@eduswiper/types';
import { spawn } from 'threads';
import { CardCollectionService } from 'libs/card-collection/src/lib/card-collection.service';
import { CropperService } from 'libs/cropper/src/lib/cropper/cropper.service';
import { BehaviorSubject } from 'rxjs';

@Injectable({
	providedIn: 'root',
})
export class CropAllService {
	croppersArray: { cropper: Cropper; id: string }[] = [];
	cropperArray = new BehaviorSubject<{ cropper: Cropper; id: string }[]>(
		this.croppersArray
	);
	cropperArray$ = this.cropperArray.asObservable();

	constructor(
		private cardCollectionService: CardCollectionService,
		private cropperService: CropperService
	) {}

	addCropperToArray(cropperObj: CropperObj) {
		this.croppersArray.push(cropperObj);
		this.cropperArray.next(this.croppersArray);
	}
	removeCropperFromArray(cardId: string) {
		this.croppersArray.forEach((cropperObj) => {
			if (cardId === cropperObj.id) {
				const index = this.croppersArray.indexOf(cropperObj);
				this.croppersArray.splice(index, 1);
				this.cropperArray.next(this.croppersArray);
			}
		});
	}

	async cropToCenter(cropperObj: CropperObj) {
		const imageData = cropperObj.cropper.getImageData();
		const containerData = cropperObj.cropper.getContainerData();
		cropperObj.cropper.reset();

		let ratio: number;

		if (imageData.naturalHeight > imageData.naturalWidth) {
			ratio = containerData.height / imageData.naturalWidth;
		} else {
			ratio = containerData.width / imageData.naturalHeight;
		}
		cropperObj.cropper.zoomTo(ratio);
		type IOnExportCanvas = (
			cropperObj: CropperObj
		) => Promise<IImageCropperResult>;
		const onExportCanvas = await spawn<IOnExportCanvas>(
			new Worker(new URL('on-export-canvas.ts', import.meta.url), {
				type: 'module',
			})
		);
		const data = await onExportCanvas(cropperObj);
		data.editedURL &&
			this.cardCollectionService.changeEditedPhoto(
				cropperObj.id,
				data.editedURL
			);
		this.changeImagesAfterCrop(data, cropperObj.id);
	}
	async cropToFit(cropperObj: CropperObj) {
		cropperObj.cropper.reset();

		type IOnExportCanvas = (
			cropperObj: CropperObj
		) => Promise<IImageCropperResult>;
		const onExportCanvas = await spawn<IOnExportCanvas>(
			new Worker(new URL('on-export-canvas.ts', import.meta.url), {
				type: 'module',
			})
		);
		const data = await onExportCanvas(cropperObj);

		data.editedURL &&
			this.cardCollectionService.changeEditedPhoto(
				cropperObj.id,
				data.editedURL
			);
		this.changeImagesAfterCrop(data, cropperObj.id);
	}

	cropToCenterAll() {
		this.croppersArray.forEach((cropperObj) => {
			this.cropToCenter(cropperObj);
		});
	}

	cropToFitAll() {
		this.croppersArray.forEach((cropperObj) => {
			this.cropToFit(cropperObj);
		});
	}
	initialCrop(cropper: Cropper, id: string) {
		const croppedCard = this.cardCollectionService.currWorkspace.cards.find(
			(card) => card.id === id && card.freshInstance
		);
		if (croppedCard) {
			croppedCard.freshInstance = false;
			this.cropToCenter({ cropper, id });
			this.cardCollectionService.updateCards();
		}
	}

	changeImagesAfterCrop(croppData: IImageCropperResult, id: string) {
		const changeData: IDataToCrop = {
			canvasTop: croppData.canvasData.top,
			canvasLeft: croppData.canvasData.left,
			canvasWidth: croppData.canvasData.width,
			canvasHeight: croppData.canvasData.height,
			imageWidth: croppData.imageData.width,
			imageHeight: croppData.imageData.height,
			imageLeft: croppData.imageData.left,
			imageTop: croppData.imageData.top,
			imageRotate: croppData.imageData.rotate,
		};
		this.cardCollectionService.changePositionImg(changeData, id);
	}
}
import {createContext, useContext} from 'react';

export type AuthContext = {
  isAuth: boolean
  setIsAuth: (b: boolean) => void
}

export const AuthContext = createContext<AuthContext>({
  isAuth: false,
  setIsAuth: () => undefined
})

export const useAuthContext = () => useContext(AuthContext)

// usage
const {isAuth, setIsAuth} = useAuthContext()

function App() {
  const [isAuth, setIsAuth] = useState(false)

  return (
    <div className="App">
      <AuthContext.Provider value={{isAuth, setIsAuth}}>
        <Header/>
      </AuthContext.Provider>
    </div>
  );
}
{
  "compilerOptions": {
    "typeRoots": [
      "node_modules/@types",
      "src/typings"
    ]
  }
}
//ENUM

enum userProfile {
  firstName = "Cheng",
  lastName = "Phansivang",
  bio = "I love virak pech my baby",
  }


const { firstName, lastName, bio} = userProfile;


//INTERFACE

interface profile{

  userName:string,
  password:number,
}


const proFile: profile = {
  userName:"Phansivang",
  password:2222,
  
}

// UNION TYPE
function texing(userName:string|number){
  console.log(userName);
}


// FUNCTION WITH VOID // VOID CAN'T RETURN THE VALUE

function userName():void{
  console.log("Phansivang");
}
userName()


// OPTIONAL PARAMETERS

function myNumber(x:number, y:number, o?:number){
  console.log(x + y + (o || 0))
}

myNumber(2,3)



// CASTING AS

const lengleng = "5454545";

console.log(typeof (lengleng as string).length)

import { useState, useEffect } from "react";

const SECOND = 1_000;
const MINUTE = SECOND * 60;
const HOUR = MINUTE * 60;
const DAY = HOUR * 24;

export default function useTimer(deadline, interval = SECOND) {
  const [timespan, setTimespan] = useState(new Date(deadline) - Date.now());

  useEffect(() => {
    const intervalId = setInterval(() => {
      setTimespan((_timespan) => _timespan - interval);
    }, interval);

    return () => {
      clearInterval(intervalId);
    };
  }, [interval]);

  /* If the initial deadline value changes */
  useEffect(() => {
    setTimespan(new Date(deadline) - Date.now());
  }, [deadline]);
  
  function checkTime(i: string | number) {
    if (i < 10) i = "0" + i
    return i;
  }

// if want 0 before number return {
  //days: checkTime( Math.floor(timespan / DAY)),
// }

  return {
    days: Math.floor(timespan / DAY),
    hours: Math.floor((timespan / HOUR) % 24),
    minutes: Math.floor((timespan / MINUTE) % 60),
    seconds: Math.floor((timespan / SECOND) % 60)
  };
}

// usage
const { days, hours, minutes, seconds } = useTimer("2022-12-31T23:59:59");

(new Date(+timeStampinSeconds * 1000).toISOString()).slice(0, 19))
const array = [item1, item2, item3]

//Idę pętlą po tablicy. Jeśli chcę, żeby kod wykonał się dla szczególnej sytuacji w item1, ale jeśli nie to dla CAŁEJ tablicy

if(item1){
  //kod, gdy item
}
//kod dla całej tablicy

//jeśli chcę wykonać kod dla warunku dla item1, a inny kod dla reszty tablicy

if(item1){
  //kod, gdy item1
}
else {
  //kod który wykona się dla reszty tablicy w pętli
}
type Numbers = [number, number];
type Strings = [string, string];
 
type NumbersAndStrings = [...Numbers, ...Strings]; 
// [number, number, string, string]

type NumberAndRest = [number, ...string[]];
// [number, varying number of string] 

type RestAndBoolean = [...any[], boolean]; 
// [varying number of any, boolean]
"eslint-config-custom": "*",
    "prettier": "latest",
    "turbo": "latest",
    "@babel/cli": "^7.18.9",
    "@babel/core": "^7.18.9",
    "@babel/plugin-transform-modules-commonjs": "^7.18.6",
    "@babel/plugin-transform-runtime": "^7.18.9",
    "@babel/preset-typescript": "^7.18.6",
    "babel-plugin-named-exports-order": "^0.0.2",
    "babel-plugin-transform-scss": "^1.1.0",
    "sass": "^1.53.0"
  },
{
  "sourceType": "unambiguous",
  "presets": [
    "@babel/preset-react",
    [
      "@babel/preset-env",
      {
        "targets": "> 0.25%, not dead"
      }
    ],
    "@babel/preset-typescript"
  ],
  "plugins": [
    "babel-plugin-transform-scss",
    [
      "@babel/plugin-transform-runtime",
      {
        "absoluteRuntime": false,
        "corejs": false,
        "helpers": true,
        "regenerator": true,
        "version": "7.0.0-beta.0"
      }
    ],
    "@babel/plugin-transform-modules-commonjs"
  ]
}
   // Delete one Asset
            .addCase(deleteAssetThunk.fulfilled, (state, action) => {
                state.assets = Object.fromEntries(Object.entries(state.assets).filter(([key]) => key !== action.payload))
                console.log('fulfilled, asset Deleted');
            })
import { useEffect, useMemo, useRef, useState } from 'react'
import { useWeb3React } from '@web3-react/core'
import Web3 from 'web3'

import { defaultEVMNetworkId } from '@contracts/networks'

import { web3NoAccountInstances } from '@utils/web3'

export const useWeb3 = () => {
  const { library, chainId } = useWeb3React()
  const web3NoAccount = useMemo(
    () =>
      web3NoAccountInstances[
        chainId ? chainId.toString() : defaultEVMNetworkId
      ],
    [chainId]
  )
  const refChainId = useRef(chainId)
  const refWeb3 = useRef(library)
  const [web3, setweb3] = useState(library ? new Web3(library) : web3NoAccount)

  useEffect(() => {
    if (library !== refWeb3.current || chainId !== refChainId.current) {
      setweb3(library ? new Web3(library) : web3NoAccount)
      refWeb3.current = library
      refChainId.current = chainId
    }
  }, [chainId, library, web3NoAccount])

  return web3
}
import { isMobile } from 'react-device-detect'
import { useWeb3 } from '@firestarter-private/firestarter-library'
import { UnsupportedChainIdError, useWeb3React } from '@web3-react/core'

import { injected, walletconnect } from '@/connectors'

export const useWalletConnect = (): { onClickWallet: () => void } => {
  const web3 = useWeb3()
  const { activate } = useWeb3React()

  const onClickWallet = () => {
    if (isMobile) {
      // if the connector is walletconnect and the user has already tried to connect, manually reset the connector
      if (
        // @ts-ignore
        walletconnect.walletConnectProvider?.wc?.uri
      ) {
        walletconnect.walletConnectProvider = undefined
      }
      activate(walletconnect, undefined, true).catch((error) => {
        if (error instanceof UnsupportedChainIdError) {
          activate(walletconnect) // a little janky...can't use setError because the connector isn't set
        }
      })
      // @ts-ignore
      web3.setProvider(window.ethereum)
    } else {
      activate(injected)
    }
  }

  return { onClickWallet }
}
typescript adds types to JavaScript.
/////////////////////////////////////////// function arguments
Function arguments & return types:
let greeting : (name: string) => string;
greeting = function (name: string) {
    return `Hi ${name}`;
};
/////////////////////////////////////////// object Type
let employee: object;
object type represents any value that is not a primitive type,while Object type describes functionalities that available on all objects;toString,valueof...

//////////////////////////////////// array & tuple
array can store mixed type values
let arr: type[]
A tupple is an array with a fixed number of elements whose types are known.

//////////////////////////////////// any type
Use the any type to store a value that you don’t actually know its type at the compile-time

//////////////////////////////////// void type
 you use the void type as the return type of functions that do not return a value. 
 
//////////////////////////////////// union types
  combine multiple types into one type
  let result: number | string;
/////////////////////////////////////////// type aliases
define a new name for an existing type,useful for union types.
type newName=existing type;
type alphanumeric = string | number;
/////////////////////////////////////////////// String Literal Types
define a type that accepts only a specified string literal;
let mouseEvent: 'click' | 'dblclick' | 'mouseup' | 'mousedown';

/////////////////////////////////////  Type inference
TypeScript guesses the type,when you initialize the variable.

/////////////////////////////////////  optional parameters
Use the parameter?: type syntax to make a parameter optional.
Use the expression typeof(parameter) !== 'undefined' to check if the parameter has been initialized.


/////////////////////////////////////  default parameters
function name(parameter1=defaultValue1,...) {
   // do something
}
To use the default initialized value of a parameter, you omit the argument when calling the function or pass the undefined into the function.

/////////////////////////////////////  classes
ES5 allows classes and Ts adds type annotations

/////////////////////////////////////  inheritance
you use the extends keyword.
To call the constructor of the parent class in the constructor of the child class, you use the super() syntax. 
Method overriding:just redefine the method

/////////////////////////////Static Methods and Properties
a static property is shared among all instances of a class.

///////////////////////////// abstract classe
define common behaviors for derived classes to extend,
  

///////////////////////////// type guards
 used to identify or narrow down the type of a variable using instanceOf and typeOf.
 User can define type-guards:
 function isCustomer(partner: any): partner is Customer {
    return partner instanceof Customer;
}
///////////////////// casting types
to convert a variable from one type to another.using as pr <>;
const fetchTrainingQueue = () => {
		const requestOptions = {
			method: 'GET',
			headers: {
				"Content-Type": "application/json",
				"Authorization": `Bearer ${props.jwt}`
			},
		};

		fetch('https://api.ai-server.becode.org/get_user_training_queue', requestOptions)
			.then(response => response.json())
			.then(data => {
				setTrainingQueue(data)
			})
	}
  useEffect(() => {
    document.querySelector('main')?.scrollTo({
      top: 0,
      left: 0,
      behavior: 'smooth',
    });
  }, [id]);
import { useState, useEffect } from 'react';
import debounce from 'lodash/debounce';

export function useScroll() {
  const [scrollY, setScrollY] = useState<number>(0);

  const listener = () => {
    setScrollY(window.pageYOffset);
  };

  const delay = 15;

  useEffect(() => {
    window.addEventListener('scroll', debounce(listener, delay));
    return () => window.removeEventListener('scroll', listener);
  });

  return {
    scrollY
  };
}
async function fetchData() {
  try {
    await Promise.resolve(42);
  } catch (err) {
    if (err instanceof Error) {
      // ✅ TypeScript knows err is Error
      console.log(err.message);
    } else {
      console.log('Unexpected error', err);
    }
  }
}
const fakeDataObj = fakeData2.reduce((obj, item) => Object.assign(obj, { [item.name]: item.valueOf() }), {}) 

const str = '4556' as string;

console.log(fakeDataObj['4556' as keyof typeof fakeDataObj]);

//back to array
const new array = []
 for (const elem in fakeDataObj.data) {
                newArray.push(fakeDataObj.data[elem as keyof typeof fakeDataObj.data])
            }
const str = 'name' as string;

const obj = {
  name: 'James Doe',
  country: 'Chile',
};

// 👇️ "James Doe"
console.log(obj[str as keyof typeof obj]);

// 👇️ type T = "name" | "country"
type T = keyof typeof obj;
$ npm install typescript --save-dev
$ npm install express
$ npm install --save-dev eslint @types/express @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-config-prettier
$ npm install --save-dev ts-node-dev

// GENERATE TSCONFIG FILE FROM TERMINAL
$npm run tsc -- --init
$tsc --init

// PACKAGE.JSON
{
  // ..
  "scripts": {
    "start": "node dist/index.js",
    "build": "tsc --build",
    "clean": "tsc --build --clean",
    "tsc": "tsc",
    "dev": "ts-node-dev index.ts",
    "lint": "eslint src/**/*.ts",
     "format": "src/**/*.ts --fix",
  },
  // ..
}

// TSCONFIG.JSON
{
  "compilerOptions": {
    "target": "ES2018",
    "outDir": "dist",
    "sourceMap": true,
    "module": "commonjs",
    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noImplicitReturns": false,
    "noFallthroughCasesInSwitch": true,
    "esModuleInterop": true,
    "resolveJsonModule": true
  },
  "include": [
    "src/**/*.ts",
  ],
  "exclude": [
    "node_modules"
  ]
}

//.ESLINTRC
{
  "root": true,
  "parser": "@typescript-eslint/parser",
  "plugins": [
    "@typescript-eslint"
  ],
  "extends": [
    "eslint:recommended",
    "plugin:@typescript-eslint/recommended",
    "prettier"
  ],
  "parserOptions": {
    "ecmaVersion": 2018,
    "sourceType": "module"
  },
  "env": {
    "browser": true,
    "es6": true,
    "node": true
  },
  "rules": {
    "indent": 0,
    "linebreak-style": 0,
    "quotes": [
      "error",
      "double"
    ]
  }
}
  
// PRETTIERRC
{
  "trailingComma": "all",
  "importOrder": [
    "<THIRD_PARTY_MODULES>",
    "next-seo.config",
    "^components/(.*)$",
    "^utils/(.*)$",
    "^assets/(.*)$",
    "^@fontsource/(.*)$",
    "^[./]"
  ],
  "importOrderSeparation": true,
  "importOrderSortSpecifiers": true
}
// custom.d.ts
declare module "*.svg" {
  import React = require('react');
  export const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>;
  const src: string;
  export default src;
}

// tsconfig
"include": [
    "src",
    "custom.d.ts"
  ]
export interface IDuration {
  readonly milliseconds: number
  readonly seconds: number
  readonly minutes: number
  readonly hours: number
  readonly days: number
}

export class Duration implements IDuration {

  readonly total: number

  constructor(input: IDuration) {
    const { days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0 } = input
    this.total = days + hours + minutes + seconds + milliseconds
  }

  static of(input: Partial<IDuration>): Duration {
    const { days = 0, hours = 0, minutes = 0, seconds = 0, milliseconds = 0 } = input
    return new Duration({
      days: days * 86400000,
      hours: hours * 3600000,
      minutes: minutes * 60000,
      seconds: seconds * 1000,
      milliseconds,
    })
  }

  add(other: Duration): Duration {
    return Duration.of({ milliseconds: this.total + other.total })
  }

  subtract(other: Duration): Duration {
    return Duration.of({ milliseconds: this.total - other.total })
  }

  get days() {
    return Math.floor(this.total / 86400000)
  }

  get hours() {
    return Math.floor(this.total / 3600000)
  }

  get minutes() {
    return Math.floor(this.total / 60000)
  }

  get seconds() {
    return Math.floor(this.total / 1000)
  }

  get milliseconds() {
    return this.total
  }
}
npm install -g gitignore
npx gitignore <language/framework/library>
  
/* npx gitignore node
npx gitignore react
npx gitignore reactNative */
module.exports = {
  globals: {
    module: true,
  },
  env: {
    browser: true,
    es6: true,
    jest: true,
  },
  extends: [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:@typescript-eslint/recommended",
  ],
  plugins: ["react", "@typescript-eslint"],
  settings: {
    react: {
      pragma: "React",
      version: "detect",
    },
  },
  rules: {
    "@typescript-eslint/explicit-function-return-type": 0,
    "@typescript-eslint/explicit-module-boundary-types": 0,
    "react/react-in-jsx-scope": 0,
  },
  'import/order': [
    2,
    {
      'newlines-between': 'always',
      groups: [
        'builtin',
        'external',
        'internal',
        'parent',
        'sibling',
        'index',
        'unknown',
        'object',
        'type',
      ],
      alphabetize: {
        order: 'asc',
        caseInsensitive: true,
      },
      pathGroups: [
        {
          pattern: 'react*',
          group: 'external',
          position: 'before',
        },
      ],
    },
  ],
};

// Add lint script to package.json
// "lint": "eslint './src/**/*.{ts,tsx}'"
npx cap open ios #abrir o projecto no xcode

npx cap open android #abrir o projecto no android
<dict>
+  <key>NSCameraUsageDescription</key>
+  <string>To be able to scan barcodes</string>
</dict>
<?xml version="1.0" encoding="utf-8"?>
<manifest
  xmlns:android="http://schemas.android.com/apk/res/android"
+  xmlns:tools="http://schemas.android.com/tools" <-- adicionas esta linha não removendo nada e seguindo esta lógica

  package="com.example">

  <application
+    android:hardwareAccelerated="true" <-- adicionas esta linha não removendo nada e seguindo esta lógica
  >
  </application>

+  <uses-permission android:name="android.permission.CAMERA" /><-- adicionas esta linha não removendo nada e seguindo esta lógica

+  <uses-sdk tools:overrideLibrary="com.google.zxing.client.android" /><-- adicionas esta linha não removendo nada e seguindo esta lógica
</manifest>
ionic build --prod

#caso quiseres colocar a app para android dás o seguinte comando:
npm install @capacitor/android
npx cap add android

#caso quiseres colocar a app para iOS dás o seguinte comando:
npm install @capacitor/ios
npx cap add ios


#no final dão estes dois ultimos comandos

npx cap sync
npx cap copy Android ou ios #dependendo do qual escolheram
...

<ion-content class="scanner-hide" *ngIf="scanStatus == false">
  <div class="padding-container center">
    <ion-button color="primary" (click)="scanCode()"><ion-icon slot="start" name="qr-code-outline"></ion-icon> Scanear Código</ion-button> <!-- Botão que chama a função do scanner-->
  </div>
  <ion-card>
    <ion-card-content><h1>{{ result }}</h1></ion-card-content> <!-- mostra o resultado do scan -->
  </ion-card>
  
  <div class="scanner-ui"> <!-- Quando estamos a scanear, chama esta classe-->
    ...Scanner Interface
    </div>
    <div class="ad-spot"></div>
</ion-content>
...
import { BarcodeScanner } from '@capacitor-community/barcode-scanner';



...



export class HomePage {
  public scanStatus:boolean = false; // no inicio da página, coloca o estado do código qr para falso
  public result:any;

  constructor() {}


  async scanCode () {

    this.setPermissions(); /* chama as permissões à camera */
  
    BarcodeScanner.hideBackground(); // coloca o fundo transparente
    this.scanStatus = true; // ao mudar esta variável para true, estamos a puxar o qr code scanner 
    document.body.classList.add("qrscanner"); // adiciona a classe css que fizemos no global
    const result = await BarcodeScanner.startScan(); // começa a fazer scan e espera por um result
  
  // se o qr scanner detectou algum número, então ele faz o código abaixo
    if (result.hasContent) {

        
        this.scanStatus = false; //como é obvio, ele tem de desligar o scanner ao obter o resultado
        BarcodeScanner.stopScan(); //para o scan
        this.result = result.content; // passa o resultado para a variável global result
        BarcodeScanner.showBackground(); //volta a mostrar o fundo
        document.body.classList.remove("qrscanner"); //remove a classe css que criamos no global
    
    }
  }

  async setPermissions(){
    const status = await BarcodeScanner.checkPermission({ force: true }); /* força a permissão para true, caso o utilizador não aceite, o scanner não funciona */
    if (status.granted) {
      // the user granted permission
      return true; // se o utilizador aceitou as permissões retorna true
    }
  
      return false; // se o utilizador não aceitou retorna false
  }
}
let max: number = 10000;

for (let n = 1; n < max; n++) {
  let dist1: number = x1 + (v1 * n);
  let dist2: number = x2 + (v2 * n);
  if (dist1 === dist2) return 'YES';        
}

return 'NO';
interface Observer{
   update:() => void;
}

class ConcreteObserverA implements Observer {
   update() {
        console.log(this.constructor.name,"has been updated");
   }
}

class ConcreteObserverB implements Observer {
   update () {
        console.log(this.constructor.name,"has been updated");
   }
}
class Subject {
    private _name = "";

    private observerCollection:Observer[] = [];

    get name() {
        return this._name;
    }

    set name(val:string) {
        this._name=val;
        this.notifyObservers();
    }

    registerObserver(...o:Observer[]) {
            this.observerCollection.push(...o);
    }

    unregisterObserver(o:Observer) { 
        this.observerCollection = this.observerCollection.filter (e => e! == o);
    }

    notifyObservers() {
        this.observerCollection.forEach(o => o.update() );
    }
}

const subject = new Subject();
const oA = new ConcreteObserverA();
const oB = new ConcreteObserverB();
subject.registerObserver(oA, oB);

subject.name = "Jau, jau!";
interface TaskConfiguration extends BaseTaskConfiguration {
  /**
   * The configuration's version number
   */
  version: '2.0.0';

  /**
   * Windows specific task configuration
   */
  windows?: BaseTaskConfiguration;

  /**
   * macOS specific task configuration
   */
  osx?: BaseTaskConfiguration;

  /**
   * Linux specific task configuration
   */
  linux?: BaseTaskConfiguration;
}

interface BaseTaskConfiguration {
  /**
   * The type of a custom task. Tasks of type "shell" are executed
   * inside a shell (e.g. bash, cmd, powershell, ...)
   */
  type: 'shell' | 'process';

  /**
   * The command to be executed. Can be an external program or a shell
   * command.
   */
  command: string;

  /**
   * Specifies whether a global command is a background task.
   */
  isBackground?: boolean;

  /**
   * The command options used when the command is executed. Can be omitted.
   */
  options?: CommandOptions;

  /**
   * The arguments passed to the command. Can be omitted.
   */
  args?: string[];

  /**
   * The presentation options.
   */
  presentation?: PresentationOptions;

  /**
   * The problem matcher to be used if a global command is executed (e.g. no tasks
   * are defined). A tasks.json file can either contain a global problemMatcher
   * property or a tasks property but not both.
   */
  problemMatcher?: string | ProblemMatcher | (string | ProblemMatcher)[];

  /**
   * The configuration of the available tasks. A tasks.json file can either
   * contain a global problemMatcher property or a tasks property but not both.
   */
  tasks?: TaskDescription[];
}

/**
 * Options to be passed to the external program or shell
 */
export interface CommandOptions {
  /**
   * The current working directory of the executed program or shell.
   * If omitted the current workspace's root is used.
   */
  cwd?: string;

  /**
   * The environment of the executed program or shell. If omitted
   * the parent process' environment is used.
   */
  env?: { [key: string]: string };

  /**
   * Configuration of the shell when task type is `shell`
   */
  shell: {
    /**
     * The shell to use.
     */
    executable: string;

    /**
     * The arguments to be passed to the shell executable to run in command mode
     * (e.g ['-c'] for bash or ['/S', '/C'] for cmd.exe).
     */
    args?: string[];
  };
}

/**
 * The description of a task.
 */
interface TaskDescription {
  /**
   * The task's name
   */
  label: string;

  /**
   * The type of a custom task. Tasks of type "shell" are executed
   * inside a shell (e.g. bash, cmd, powershell, ...)
   */
  type: 'shell' | 'process';

  /**
   * The command to execute. If the type is "shell" it should be the full
   * command line including any additional arguments passed to the command.
   */
  command: string;

  /**
   * Whether the executed command is kept alive and runs in the background.
   */
  isBackground?: boolean;

  /**
   * Additional arguments passed to the command. Should be used if type
   * is "process".
   */
  args?: string[];

  /**
   * Defines the group to which this task belongs. Also supports to mark
   * a task as the default task in a group.
   */
  group?: 'build' | 'test' | { kind: 'build' | 'test'; isDefault: boolean };

  /**
   * The presentation options.
   */
  presentation?: PresentationOptions;

  /**
   * The problem matcher(s) to use to capture problems in the tasks
   * output.
   */
  problemMatcher?: string | ProblemMatcher | (string | ProblemMatcher)[];

  /**
   * Defines when and how a task is run.
   */
  runOptions?: RunOptions;
}

interface PresentationOptions {
  /**
   * Controls whether the task output is reveal in the user interface.
   * Defaults to `always`.
   */
  reveal?: 'never' | 'silent' | 'always';

  /**
   * Controls whether the command associated with the task is echoed
   * in the user interface. Defaults to `true`.
   */
  echo?: boolean;

  /**
   * Controls whether the panel showing the task output is taking focus.
   * Defaults to `false`.
   */
  focus?: boolean;

  /**
   * Controls if the task panel is used for this task only (dedicated),
   * shared between tasks (shared) or if a new panel is created on
   * every task execution (new). Defaults to `shared`.
   */
  panel?: 'shared' | 'dedicated' | 'new';

  /**
   * Controls whether to show the `Terminal will be reused by tasks,
   * press any key to close it` message.
   */
  showReuseMessage?: boolean;

  /**
   * Controls whether the terminal is cleared before this task is run.
   * Defaults to `false`.
   */
  clear?: boolean;

  /**
   * Controls whether the task is executed in a specific terminal
   * group using split panes. Tasks in the same group (specified by a string value)
   * will use split terminals to present instead of a new terminal panel.
   */
  group?: string;
}

/**
 * A description of a problem matcher that detects problems
 * in build output.
 */
interface ProblemMatcher {
  /**
   * The name of a base problem matcher to use. If specified the
   * base problem matcher will be used as a template and properties
   * specified here will replace properties of the base problem
   * matcher
   */
  base?: string;

  /**
   * The owner of the produced VS Code problem. This is typically
   * the identifier of a VS Code language service if the problems are
   * to be merged with the one produced by the language service
   * or 'external'. Defaults to 'external' if omitted.
   */
  owner?: string;

  /**
   * The severity of the VS Code problem produced by this problem matcher.
   *
   * Valid values are:
   *   "error": to produce errors.
   *   "warning": to produce warnings.
   *   "info": to produce infos.
   *
   * The value is used if a pattern doesn't specify a severity match group.
   * Defaults to "error" if omitted.
   */
  severity?: string;

  /**
   * Defines how filename reported in a problem pattern
   * should be read. Valid values are:
   *  - "absolute": the filename is always treated absolute.
   *  - "relative": the filename is always treated relative to
   *    the current working directory. This is the default.
   *  - ["relative", "path value"]: the filename is always
   *    treated relative to the given path value.
   *  - "autodetect": the filename is treated relative to
   *    the current workspace directory, and if the file
   *    does not exist, it is treated as absolute.
   *  - ["autodetect", "path value"]: the filename is treated
   *    relative to the given path value, and if it does not
   *    exist, it is treated as absolute.
   */
  fileLocation?: string | string[];

  /**
   * The name of a predefined problem pattern, the inline definition
   * of a problem pattern or an array of problem patterns to match
   * problems spread over multiple lines.
   */
  pattern?: string | ProblemPattern | ProblemPattern[];

  /**
   * Additional information used to detect when a background task (like a watching task in Gulp)
   * is active.
   */
  background?: BackgroundMatcher;
}

/**
 * A description to track the start and end of a background task.
 */
interface BackgroundMatcher {
  /**
   * If set to true the watcher is in active mode when the task
   * starts. This is equals of issuing a line that matches the
   * beginPattern.
   */
  activeOnStart?: boolean;

  /**
   * If matched in the output the start of a background task is signaled.
   */
  beginsPattern?: string;

  /**
   * If matched in the output the end of a background task is signaled.
   */
  endsPattern?: string;
}

interface ProblemPattern {
  /**
   * The regular expression to find a problem in the console output of an
   * executed task.
   */
  regexp: string;

  /**
   * Whether the pattern matches a problem for the whole file or for a location
   * inside a file.
   *
   * Defaults to "location".
   */
  kind?: 'file' | 'location';

  /**
   * The match group index of the filename.
   */
  file: number;

  /**
   * The match group index of the problem's location. Valid location
   * patterns are: (line), (line,column) and (startLine,startColumn,endLine,endColumn).
   * If omitted the line and column properties are used.
   */
  location?: number;

  /**
   * The match group index of the problem's line in the source file.
   * Can only be omitted if location is specified.
   */
  line?: number;

  /**
   * The match group index of the problem's column in the source file.
   */
  column?: number;

  /**
   * The match group index of the problem's end line in the source file.
   *
   * Defaults to undefined. No end line is captured.
   */
  endLine?: number;

  /**
   * The match group index of the problem's end column in the source file.
   *
   * Defaults to undefined. No end column is captured.
   */
  endColumn?: number;

  /**
   * The match group index of the problem's severity.
   *
   * Defaults to undefined. In this case the problem matcher's severity
   * is used.
   */
  severity?: number;

  /**
   * The match group index of the problem's code.
   *
   * Defaults to undefined. No code is captured.
   */
  code?: number;

  /**
   * The match group index of the message. Defaults to 0.
   */
  message: number;

  /**
   * Specifies if the last pattern in a multi line problem matcher should
   * loop as long as it does match a line consequently. Only valid on the
   * last problem pattern in a multi line problem matcher.
   */
  loop?: boolean;
}

/**
 * A description to when and how run a task.
 */
interface RunOptions {
  /**
   * Controls how variables are evaluated when a task is executed through
   * the Rerun Last Task command.
   * The default is `true`, meaning that variables will be re-evaluated when
   * a task is rerun. When set to `false`, the resolved variable values from
   * the previous run of the task will be used.
   */
  reevaluateOnRerun?: boolean;

  /**
   * Specifies when a task is run.
   *
   * Valid values are:
   *   "default": The task will only be run when executed through the Run Task command.
   *   "folderOpen": The task will be run when the containing folder is opened.
   */
  runOn?: string;
}
import { Directive, TemplateRef, ViewContainerRef, Input} from '@angular/core';

@Directive({
  selector: '[appNavigationLine]'
})
export class NavigationLineDirective {

  constructor(
    private templateRef: TemplateRef<any>,
    private viewContainer: ViewContainerRef
  ) { }

  @Input('appNavigationLine') set navigationLine(numArray: (number|string)[]) {
    this.viewContainer.clear()
    numArray.forEach( num => this.viewContainer.createEmbeddedView(this.templateRef, {
      index: numArray.indexOf(num)
    }))
  }
}
class CPF {
    cpfNumber: Array<number> = [];
    
    notAcepted: Array<string> = [
        "00000000000", "11111111111", "22222222222", "33333333333", "44444444444",
        "55555555555", "66666666666", "77777777777", "88888888888", "99999999999"
    ];

    generate(): string {
        let number = [];
        for (let i = 0; i < 9; i++) {
            number.push(Math.floor(Math.random() * 10));
        }
        number.push(this.claculateFirstDigit(number));
        number.push(this.claculateSecondDigit(number));
        return this.maskCPF(number);
    }
    maskCPF(values: Array<number>): string {
        let cpf = "";
        for (let item of values) {
            cpf += item;
        }
        cpf = cpf.replace(/[^\d]/g, '').replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4');
        return cpf;
    }
    clean(values: string) {
        values = values.replace(/[^\d]/g, '');
        for (let item of values) {
            this.cpfNumber.push(parseInt(item));
        }
    }
    claculateFirstDigit(values: Array<number>): number {
        let sum = 0;
        for (let i = 0; i < 9; i++) {
            sum += values[i] * (10 - i);
        }
        let rest = (sum * 10) % 11;
        if (rest === 10 || rest === 11) {
            rest = 0;
        }
        return rest;
    }
    claculateSecondDigit(values: Array<number>): number {
        let sum = 0;
        for (let i = 0; i < 10; i++) {
            sum += values[i] * (11 - i);
        }
        let rest = (sum * 10) % 11;
        if (rest === 10 || rest === 11) {
            rest = 0;
        }
        return rest;
    }
    isValid(values: string): boolean {
        this.clean(values);
        return this.isAcepted(values) && this.length(this.cpfNumber) 
        && this.validate(this.cpfNumber);
    }
    isAcepted(values: string): boolean {
        let cpf = values.replace(/[^\d]/g, '');
        return !this.notAcepted.includes(cpf);
    }
    length(values: Array<number>): boolean {
        return values.length === 11;
    }
    validate(values: Array<number>): boolean {
        return this.claculateFirstDigit(values) === this.cpfNumber[9] 
        && this.claculateSecondDigit(values) === this.cpfNumber[10];
    }
    origin(values: string): string {
        this.clean(values);
        switch (this.cpfNumber[8]) {
            case 0:
                return "Rio Grande do Sul";
            case 1:
                return "Distrito Federal, Goiás, Mato Grosso do Sul e Tocantins";
            case 2:
                return "Pará, Amazonas, Acre, Amapá, Rondônia e Roraima";
            case 3:
                return "Ceará, Maranhão e Piauí";
            case 4:
                return "Pernambuco, Rio Grande do Norte, Paraíba e Alagoas";
            case 5:
                return "Bahia e Sergipe";
            case 6:
                return "Minas Gerais";
            case 7:
                return "Rio de Janeiro e Espírito Santo";
            case 8:
                return "São Paulo";
            case 9:
                return "Paraná e Santa Catarina";
            default:
                return "";
        }
    }
}

var cpf = new CPF();
let mockCpf = cpf.generate();      // gera um cpf mock.
let valid = cpf.isValid(mockCpf);  // verifica se o cpf é valido.
let origem = cpf.origin(mockCpf);  // verifica pelo digito de onde pertence.
console.log(mockCpf);              // mostra um o cpf gerado em formato ###.###.###-##
const Algorithm = {
    clean: (number) => {
        if (Array.isArray(number)) {
            return number;
        }
        let array = [];
        number = number.replace(/[^\d]/g, '');

        for (let item of number) {
            array.push(parseInt(item));
        }
        return array;
    },
    notAcepted: [
        "00000000000", "11111111111", "22222222222", "33333333333", "44444444444",
        "55555555555", "66666666666", "77777777777", "88888888888", "99999999999"
    ],
    length: (number) => {
        return number.length === 11;
    },
    claculateFirstDigit: (number) => {
        let sum = 0;
        for (let i = 0; i < 9; i++) {
            sum += parseInt(number[i]) * (10 - i);
        }
        let rest = (sum * 10) % 11;
        if (rest === 10 || rest === 11) {
            rest = 0;
        }
        return rest;
    },
    claculateSecondDigit: (number) => {
        let sum = 0;
        for (let i = 0; i < 10; i++) {
            sum += parseInt(number[i]) * (11 - i);
        }
        let rest = (sum * 10) % 11;
        if (rest === 10 || rest === 11) {
            rest = 0;
        }
        return rest;
    },
    validate: (number) => {
        return Algorithm.claculateFirstDigit(number) == number[9] && Algorithm.claculateSecondDigit(number) == number[10];
    },
    isAcepted: (number) => {
        return Algorithm.notAcepted.indexOf(number) === -1;
    },
    isValid: (number) => {
        number = Algorithm.clean(number);
        return Algorithm.isAcepted(number) && Algorithm.length(number) && Algorithm.validate(number);
    },
    generate: () => {
        let number = [];
        for (let i = 0; i < 9; i++) {
            number.push(Math.floor(Math.random() * 10));
        }
        number.push(Algorithm.claculateFirstDigit(number));
        number.push(Algorithm.claculateSecondDigit(number));
        return Algorithm.maskCPF(number);
    },
    maskCPF: (number) => {
        number = Algorithm.clean(number);
        return number.slice(0, 3).join("") + "." + number.slice(3, 6).join("") + "." + number.slice(6, 9).join("") + "-" + number.slice(9, 11).join("");
    },
    origem: (number) => {
        let origem = {
            0: "Rio Grande do Sul",
            1: "Distrito Federal, Goiás, Mato Grosso do Sul e Tocantins",
            2: "Pará, Amazonas, Acre, Amapá, Rondônia e Roraima",
            3: "Ceará, Maranhão e Piauí",
            4: "Pernambuco, Rio Grande do Norte, Paraíba e Alagoas",
            5: "Bahia e Sergipe",
            6: "Minas Gerais",
            7: "Rio de Janeiro e Espírito Santo",
            8: "São Paulo",
            9: "Paraná e Santa Catarina",
        };
        return origem[number[8]];
    }
};
const partsOfTheDay = () => {
    let hour = new Date().getHours();
    let text = ["It's morning", "It's afternoon", "It's evening", "It's night"];
    var timeOfDay = text[hour < 12 ? 0 : hour < 18 ? 1 : hour < 22 ? 2 : 3];
    return timeOfDay;
}
const reverse = (str: string) => {
    return str.split('').reverse().join('');
}
console.log(reverse('Hello World'));
const hello = (name: string) => {
    return `Hello ${name}`;
}
console.log(hello('World'));
 export const useLocalStorageState = <T, K = any>(
   key: string,
   defaultValue: T | null,
   mutationFn: (value: T, optionalValue?: K) => T
 ) => {
   const localStorageValue = useLocalStorage<T>(key, (value) => {
  	 return value !== null ? JSON.parse(value) : defaultValue;
   });
   const [stateValue, setStateValue] = useState(localStorageValue);

   const setLocalStorageValue = (optionalValue?: K) => {
     const mutatedValue = mutationFn(stateValue, optionalValue);

     window.localStorage.setItem(key, JSON.stringify(mutatedValue));
     setStateValue(mutatedValue);
   };
   return { value: localStorageValue, set: setLocalStorageValue };
 };
import { Component } from '@angular/core';

@Component({
  selector: 'app-animated-project-title',
  templateUrl: './animated-project-title.component.html',
  styleUrls: ['./animated-project-title.component.css']
})
export class AnimatedProjectTitleComponent {

  constructor() { }

}
/^(?!00)(?!\.)[0-9]*\.?[0-9]*$/ только цифры и точка, не может начинаться с 00 или .

export const useNumericInput = () => {
  const [value, setValue] = useState<string>('')

  const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const rgx = /^[0-9]*\.?[0-9]*$/
    const inputValue = e.target.value
    if (!inputValue.match(rgx) || inputValue.charAt(0) === '.' || inputValue.charAt(1) === '0') {
      return setValue(prevState => prevState)
    }
    return setValue(inputValue)
  };

  return { onChange, value }
};

/// ИЛИ чистый js

export const numericInputValidator = (e: React.ChangeEvent<HTMLInputElement>, inputId: string) => {
  const userInput = e.target.value
  // @ts-ignore
  const input: HTMLInputElement = document.getElementById(inputId)

  if (userInput.charAt(1) === '0') {
    input.value = '0'
  }
  if (userInput.charAt(0) === '.') {
    input.value = ''
  }
  input.value = input.value.replace(/[^0-9\.]/g,'');
  input.addEventListener("blur", () => {
    input.value = stringTrim(userInput, 10);
  });
  input.addEventListener("focus", () => {
    input.value = userInput
  })
};

enum Direction {
  Up = 1,
  Down,
  Left,
  Right,
}
Try
export const validationSchema = (): FormValidationSchema => {
  const validationObject: { [key: string]: StringSchema } = {}

  // validation schema keys based on the name prop of the radio buttons in the form
  HOBBIES.forEach((hobby) => {
    validationObject[hobby.stateName] = Yup.string().required()
  })

  return Yup.object(validationObject)
}
class _Array<T> extends Array<T> {
  static range(from: number, to: number, step: number): number[] {
    return [...Array(Math.floor((to - from) / step) + 1)].map(
      (v, k) => from + k * step
    );
  }
}
_Array.range(0, 9, 1);
interface _Iterable extends Iterable<{}> {
  length: number;
}

class _Array<T> extends Array<T> {
  static range(from: number, to: number, step: number): number[] {
    return Array.from(
      <_Iterable>{ length: Math.floor((to - from) / step) + 1 },
      (v, k) => from + k * step
    );
  }
}
_Array.range(0, 9, 1);
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
const Range2 = function* (to = 0, step = 1, from = 0) {
  let i = 0,
    length = Math.floor((to - from) / step) + 1;
  while (i < length) yield from + i++ * step;
};

[...Range2(5, -2, 10)]; // From 10 to 5 with step -2
//=> [10, 8, 6]

let even4to10 = Range2(10, 2, 4);
even4to10.next().value;
//=> 4
even4to10.next().value;
//=> 6
even4to10.next().value;
//=> 8
even4to10.next().value;
//=> 10
even4to10.next().value;
//=> undefined
class Range2 {
  constructor(to = 0, step = 1, from = 0) {
    this[Symbol.iterator] = function* () {
      let i = 0,
        length = Math.floor((to - from) / step) + 1;
      while (i < length) yield from + i++ * step;
    };
  }
}
[...new Range2(5)]; // First 5 Whole Numbers
//=> [0, 1, 2, 3, 4, 5]

[...new Range2(5, 2)]; // From 0 to 5 with step 2
//=> [0, 2, 4]

[...new Range2(5, -2, 10)]; // From 10 to 5 with step -2
//=> [10, 8, 6]
const Range = function* (total = 0, step = 1, from = 0) {
  for (let i = 0; i < total; yield from + i++ * step) {}
};

Array.from(Range(5, -2, -10));
//=> [-10, -12, -14, -16, -18]

[...Range(5, -2, -10)]; // Five Elements With Step -2 From -10
//=> [-10, -12, -14, -16, -18]

// Also works with for..of loop
for (i of Range(5, -2, 10)) console.log(i);
// 10 8 6 4 2

// Lazy loaded way
const number0toInf = Range(Infinity);
number0toInf.next().value;
//=> 0
number0toInf.next().value;
//=> 1
// ...
class Range {
  constructor(total = 0, step = 1, from = 0) {
    this[Symbol.iterator] = function* () {
      for (let i = 0; i < total; yield from + i++ * step) {}
    };
  }
}

[...new Range(5)]; // Five Elements
//=> [0, 1, 2, 3, 4]
[...new Range(5, 2)]; // Five Elements With Step 2
//=> [0, 2, 4, 6, 8]
[...new Range(5, -2, 10)]; // Five Elements With Step -2 From 10
//=>[10, 8, 6, 4, 2]
[...new Range(5, -2, -10)]; // Five Elements With Step -2 From -10
//=> [-10, -12, -14, -16, -18]

// Also works with for..of loop
for (i of new Range(5, -2, 10)) console.log(i);
// 10 8 6 4 2
const range = (from, to, step) =>
  [...Array(Math.floor((to - from) / step) + 1)].map((_, i) => from + i * step);

range(0, 9, 2);
//=> [0, 2, 4, 6, 8]

// can also assign range function as static method in Array class (but not recommended )
Array.range = (from, to, step) =>
  [...Array(Math.floor((to - from) / step) + 1)].map((_, i) => from + i * step);

Array.range(2, 10, 2);
//=> [2, 4, 6, 8, 10]

Array.range(0, 10, 1);
//=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Array.range(2, 10, -1);
//=> []

Array.range(3, 0, -1);
//=> [3, 2, 1, 0]
[...Array(10)].map((_, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]

Array.from(Array(10)).map((_, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]

Array.from(Array(10).keys()).map(i => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]

[...Array(10).keys()].map(i => 4 + i * -2);
//=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]

Array(10).fill(0).map((_, i) => 4 + i * 2);
//=> [4, 6, 8, 10, 12, 14, 16, 18, 20, 22]

Array(10).fill().map((_, i) => 4 + i * -2);
//=> [4, 2, 0, -2, -4, -6, -8, -10, -12, -14]
// package.json
"devDependencies": {
    "@typescript-eslint/eslint-plugin": "^5.11.0",
    "@typescript-eslint/parser": "^5.11.0",
    "eslint": "^8.8.0",
    "eslint-config-airbnb": "^19.0.4",
    "eslint-config-prettier": "^8.3.0",
    "eslint-plugin-import": "^2.25.4",
    "eslint-plugin-jest-dom": "^4.0.1",
    "eslint-plugin-jsx-a11y": "^6.5.1",
    "eslint-plugin-prettier": "^4.0.0",
    "eslint-plugin-react": "^7.28.0",
    "eslint-plugin-react-hooks": "^4.3.0",
    "eslint-plugin-simple-import-sort": "^7.0.0",
    "eslint-plugin-testing-library": "^5.0.5",
    "prettier": "^2.5.1"
  }

// .eslintrc.json
{
  "env": {
    "browser": true,
    "es2021": true,
    "jest": true
  },
  "extends": [
    "airbnb",
    "plugin:react/recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:testing-library/react",
    "plugin:jest-dom/recommended",
    "plugin:prettier/recommended"
  ],
  "parser": "@typescript-eslint/parser",
  "parserOptions": {
    "ecmaFeatures": {
      "jsx": true
    },
    "ecmaVersion": "latest",
    "sourceType": "module",
    "project": "tsconfig.json"
  },
  "settings": {
    "import/resolver": {
      "node": {
        "extensions": [".js", ".jsx", ".ts", ".tsx"],
        "paths": ["src"]
      }
    }
  },
  "plugins": [
    "react",
    "@typescript-eslint",
    "testing-library",
    "jest-dom",
    "simple-import-sort",
    "prettier"
  ],
  "rules": {
    "react/jsx-filename-extension": [1, { "extensions": [".tsx", ".jsx"] }],
    "testing-library/await-async-query": "error",
    "testing-library/no-await-sync-query": "error",
    "testing-library/prefer-user-event": "error",
    "testing-library/no-debugging-utils": "warn",
    "react/react-in-jsx-scope": "off",
    "import/extensions": ["error", "never"],
    "simple-import-sort/imports": "error",
    "simple-import-sort/exports": "error",
    "sort-imports": "off",
    "import/order": "off",
    "no-console": "warn",
    "@typescript-eslint/prefer-optional-chain": "warn",
    "@typescript-eslint/prefer-nullish-coalescing": "warn",
    "@typescript-eslint/no-for-in-array": "warn",
    "@typescript-eslint/prefer-for-of": "warn",
    "@typescript-eslint/no-floating-promises": "warn",
    "@typescript-eslint/promise-function-async": "warn",
    "@typescript-eslint/sort-type-union-intersection-members": "warn",
    "@typescript-eslint/no-unnecessary-boolean-literal-compare": "warn",
    "@typescript-eslint/no-confusing-non-null-assertion": "warn",
    "@typescript-eslint/no-non-null-asserted-nullish-coalescing": "warn",
    "@typescript-eslint/consistent-indexed-object-style": [
      "warn",
      "index-signature"
    ]
  }
}
// .vscode/settings.json
{
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}
import {
  render as rtlRender,
  RenderOptions,
  RenderResult,
} from "@testing-library/react";
import { ReactElement } from "react";
import { Provider } from "react-redux";

import { configureStoreWithMiddlewares, RootState } from "../app/store";

type CustomRenderOptions = {
  preloadedState?: RootState;
  renderOptions?: Omit<RenderOptions, "wrapper">;
};

const render = (
  ui: ReactElement,
  { preloadedState = {}, ...renderOptions }: CustomRenderOptions = {}
): RenderResult => {
  const store = configureStoreWithMiddlewares(preloadedState);
  const Wrapper: React.FC = ({ children }) => {
    return <Provider store={store}>{children}</Provider>;
  };
  return rtlRender(ui, { wrapper: Wrapper, ...renderOptions });
};

export * from "@testing-library/react";
export { render };
type KeysOfType<T, K> = { [P in keyof T]: T[P] extends K ? P : never }[keyof T];

type PostStringKeys = KeysOfType<Post, string>;
type PostNumberKeys = KeysOfType<Post, number>;
import { object, SchemaOf, string } from 'yup';

interface BaseBootstrapSchema {  
  APPLICATION_NAME: string;
  LOG_PATH: string;
}

const bootstrapValidationSchema: SchemaOf<BaseBootstrapSchema> = object({
  LOG_PATH: string().required("The 'LOG_PATH' ENV variable is required"),
  APPLICATION_NAME: string().required("The 'APPLICATION_NAME' ENV variable is required"),
});

module.exports = (schema: SchemaOf<BaseBootstrapSchema>) =>
  new Promise((resolve, reject) =>
    schema
      .validate(process.env, { abortEarly: false })
      .then(() => resolve(true))
      .catch((error: any) => {
        if (error.errors.length > 1) {
          reject(new Error(`${error.message},\n${error.errors.join(',\n')}`));
        } else {
          reject(new Error(error.message));
        }
      })
  );
    ${({ expanded }) =>
      !expanded &&
      css`
        &::after {
          content: '';
          width: 100%;
          height: 100%;
          position: absolute;
          background: white;
          inset: 0;
        }
    `}
 mockUseFilters.mockReturnValue({
      filterByGroup: jest.fn((query: string) => mockAxios.get('/api', { config: { data: query } }))
    })
let getByText: any;

describe('test', () => {
    beforeEach(() => {
      ({ getByText } = render(<Component />));
    })});
type RequiredKeys<T> = { [K in keyof T]-?: {} extends { [P in K]: T[K] } ? never : K }[keyof T];

type OptionalKeys<T> = { [K in keyof T]-?: {} extends { [P in K]: T[K] } ? K : never }[keyof T];

type PickRequired<T> = Pick<T, RequiredKeys<T>>;

type PickOptional<T> = Pick<T, OptionalKeys<T>>;

type Nullable<T> = { [P in keyof T]: T[P] | null };

type NullableOptional<T> = PickRequired<T> & Nullable<PickOptional<T>>;
interface Props {
  isFixed?: boolean
}

interface Attrs {
  type?: string
}

const Button = styled.button.attrs(({ type = 'button' }: Attrs) => ({
  type,
}))`
  position: ${({ isFixed = false }: Props) => (isFixed ? 'fixed' : 'absolute')};
`

export default () => (
  <div>
    <Button isFixed={true} type="submit">
      I'm a button with type "submit" instead of default type of "button"
    </Button>
  </div>
)
export function toTitleCase(str: string) {
  return str.toLowerCase().replace(/\b(\w)/g, s => s.toUpperCase());
}
// Example 4051231234 -> (405) 123-1234
export const formatToUSPhoneNumber = (e: React.ChangeEvent<HTMLInputElement>): string => {
  const phoneField = e.target;

  const cursorPosition = phoneField.selectionStart;
  const numericString = phoneField.value.replace(/\D/g, '').substring(0, 10);

  const match = numericString.match(/^(\d{1,3})(\d{0,3})(\d{0,4})$/);

  if (match) {
    let newVal = '(' + match[1];
    newVal += match[2] ? ') ' + match[2] : '';
    newVal += match[3] ? '-' + match[3] : '';

    // to help us put the cursor back in the right place
    const delta = newVal.length - Math.min(phoneField.value.length, 14);
    phoneField.value = newVal;
    if (cursorPosition) {
      phoneField.selectionEnd = cursorPosition + delta;
    }
  } else {
    phoneField.value = '';
  }

  return phoneField.value;
};
module.exports = {
  presets: [["next/babel"]],
  plugins: [["import", { libraryName: "antd", style: true }]],
};
import type { AppProps } from "next/app";
import "styles/variables.less";
import "styles/style.sass";

function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

export default MyApp;
@import "~antd/lib/style/themes/default.less";
@import "~antd/dist/antd.less"; // Import Ant Design styles

@primary-color: #10f5e2; // primary color for all components
@link-color: #10f5e2; // link color
@success-color: #60f7ca; // success state color
@warning-color: #faad14; // warning state color
@error-color: #f5222d; // error state color
@font-size-base: 14px; // major text font size
@heading-color: rgba(0, 0, 0, 0.85); // heading text color
@text-color: rgba(0, 0, 0, 0.65); // major text color
@text-color-secondary: rgba(0, 0, 0, 0.45); // secondary text color
@disabled-color: rgba(0, 0, 0, 0.25); // disable state color
@border-radius-base: 2px; // major border radius
@border-color-base: #d9d9d9; // major border color
@box-shadow-base: 0 3px 6px -4px rgba(0, 0, 0, 0.12),
  0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05); // major shadow for layers
/** @type {import('next').NextConfig} */
const withBundleAnalyzer = require("@next/bundle-analyzer")({
  enabled: process.env.ANALYZE === "true",
});

const withAntdLess = require("next-plugin-antd-less");

module.exports = withBundleAnalyzer(
  withAntdLess({
    // Or better still you can specify a path to a file
    lessVarsFilePath: "./styles/variables.less",
    // optional
    lessVarsFilePathAppendToEndOfContent: false,
    // optional https://github.com/webpack-contrib/css-loader#object
    cssLoaderOptions: {},

    // Other Config Here...

    webpack(config) {
      return config;
    },

    // ONLY for Next.js 10, if you use Next.js 11, delete this block
    future: {
      webpack5: true,
    },
    reactStrictMode: true
  })
);
import React from "react";
import { Checkbox } from "antd";

function onChange(checkedValues: any) {
  console.log("checked = ", checkedValues);
}

const ChecboxComponent = () => {
  const plainOptions = ["Apple", "Pear", "Orange"];
  const options = [
    { label: "Apple", value: "Apple" },
    { label: "Pear", value: "Pear" },
    { label: "Orange", value: "Orange" },
  ];
  const optionsWithDisabled = [
    { label: "Apple", value: "Apple" },
    { label: "Pear", value: "Pear" },
    { label: "Orange", value: "Orange", disabled: false },
  ];
  return (
    <>
      <Checkbox.Group
        options={plainOptions}
        defaultValue={["Apple"]}
        onChange={onChange}
      />
      <br />
      <br />
      <Checkbox.Group
        options={options}
        defaultValue={["Pear"]}
        onChange={onChange}
      />
      <br />
      <br />
      <Checkbox.Group
        options={optionsWithDisabled}
        disabled
        defaultValue={["Apple"]}
        onChange={onChange}
      />
    </>
  );
};

export default ChecboxComponent;
import React from 'react'
import { Badge, Space, Switch } from "antd";
import { ClockCircleOutlined } from "@ant-design/icons";


const BadgeComponent = () => {
    const [show, setShow] = React.useState(true);

    return (
      <Space>
        <Switch checked={show} onChange={() => setShow(!show)} />
        <Badge count={show ? 25 : 0} />
        <Badge
          count={
            show ? <ClockCircleOutlined style={{ color: "#f5222d" }} /> : 0
          }
        />
        <Badge
          className="site-badge-count-109"
          count={show ? 109 : 0}
          style={{ backgroundColor: "#52c41a" }}
        />
      </Space>
    );
}

export default BadgeComponent
import React from "react";
import { Button, Tooltip } from "antd";
import { SearchOutlined } from "@ant-design/icons";
const ButtonComponent = () => {
  return (
    <div className="button-container">
      <Tooltip title="search">
        <Button type="primary" shape="circle" icon={<SearchOutlined />} />
      </Tooltip>
      <Button type="primary" shape="circle">
        A
      </Button>
      <Button type="primary" icon={<SearchOutlined />}>
        Search
      </Button>
      <Tooltip title="search">
        <Button shape="circle" icon={<SearchOutlined />} />
      </Tooltip>
      <Button icon={<SearchOutlined />}>Search</Button>
      <br />
      <Tooltip title="search">
        <Button shape="circle" icon={<SearchOutlined />} />
      </Tooltip>
      <Button icon={<SearchOutlined />}>Search</Button>
      <Tooltip title="search">
        <Button type="dashed" shape="circle" icon={<SearchOutlined />} />
      </Tooltip>
      <Button type="dashed" icon={<SearchOutlined />}>
        Search
      </Button>
      <Button icon={<SearchOutlined />} href="https://www.google.com" />
      <br />
      <br />
      <Tooltip title="search">
        <Button
          type="primary"
          shape="circle"
          icon={<SearchOutlined />}
          size="large"
        />
      </Tooltip>
      <Button type="primary" shape="circle" size="large">
        A
      </Button>
      <Button type="primary" icon={<SearchOutlined />} size="large">
        Search
      </Button>
      <Tooltip title="search">
        <Button shape="circle" icon={<SearchOutlined />} size="large" />
      </Tooltip>
      <Button icon={<SearchOutlined />} size="large">
        Search
      </Button>
      <br />
      <Tooltip title="search">
        <Button shape="circle" icon={<SearchOutlined />} size="large" />
      </Tooltip>
      <Button icon={<SearchOutlined />} size="large">
        Search
      </Button>
      <Tooltip title="search">
        <Button
          type="dashed"
          shape="circle"
          icon={<SearchOutlined />}
          size="large"
        />
      </Tooltip>
      <Button type="dashed" icon={<SearchOutlined />} size="large">
        Search
      </Button>
      <Button
        icon={<SearchOutlined />}
        size="large"
        href="https://www.google.com"
      />
    </div>
  );
};

export default ButtonComponent;
import type { NextPage } from "next";
import Head from "next/head";
import { Tabs } from "antd";
import ButtonComponent from "components/ButtonComponent";
import BadgeComponent from "components/BadgeComponent";
import ChecboxComponent from "components/ChecboxComponent";

const Home: NextPage = () => {
  return (
    <div className="container">
      <Head>
        <title>Latihan Antd Custom Varibale</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>

      <main className="main">
        <Tabs defaultActiveKey="1">
          <Tabs.TabPane tab="Komponen Button" key="1">
            <ButtonComponent />
          </Tabs.TabPane>
          <Tabs.TabPane tab="Komponen Badge" key="2">
            <BadgeComponent />
          </Tabs.TabPane>
          <Tabs.TabPane tab="Komponen Checkbox" key="3">
            <ChecboxComponent />
          </Tabs.TabPane>
        </Tabs>
      </main>
    </div>
  );
};

export default Home;
import '../styles/globals.css'
import type { AppProps } from 'next/app'
import "antd/dist/antd.css";

function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />
}

export default MyApp
interface SuperComponentProps {
  test1: {
    a: "1" | "2"
  },
  test2: {
    a: "3" | "4"
  }
  helloworld: {
    b: "4" | "b"
  }
};

function SuperComponent<T extends SuperComponentProps[keyof SuperComponentProps]>(props: T) {
  return <p>test 3</p>;
}

// HOW TO USE
<SuperComponent<SuperComponentProps["test1"]> a="1" />
import thunk, { ThunkDispatch } from 'redux-thunk'

export type IRootThunkDispatch = ThunkDispatch<IRootState, null, IRootAction>

const store = createStore<IRootState,IRootAction,{},{}>(
    rootReducer,
    composeEnhancers(
        applyMiddleware(logger),
        applyMiddleware(routerMiddleware(history)),
        applyMiddleware(thunk),
    )
);

export default store;
// store.ts
import {
  RouterState,
  connectRouter,
  routerMiddleware,
  CallHistoryMethodAction
} from 'connected-react-router';
import { createBrowserHistory } from 'history';

export const history = createBrowserHistory();

export interface IRootState{
    board: IBoardState,
    score: IScoreState
    router: RouterState
}

const rootReducer = combineReducers<IRootState>({
    board: boardReducers,
    score: scoreReducers,
    router: connectRouter(history)
});

type  IRootAction = ... | CallHistoryMethodAction;
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

let store = createStore<IRootState,IRootAction,{},{}>(
                rootReducer,
                composeEnhancers(
                    applyMiddleware(logger),
                    applyMiddleware(routerMiddleware(history))
                )
            );

export default store;


//-----------------------------------------
// App.tsx
import { ConnectedRouter } from 'connected-react-router';
import { history } from './store';
import { Link } from 'react-router-dom';
/*Other imports are omitted for simplicity reason*/

class App extends React.Component {
  public render() {
    return (
      <Provider store={store}>
        <ConnectedRouter history={history}>
          <div>
            <nav className="nav-bar">
              <Link to="/" className="link">Home</Link>
              <Link to="/board" className="link">Open Board</Link>
              <Link to="/scores" className="link">Score Board</Link>
              <Link to="/about" className="link">About us</Link>
            </nav>
            <div>
                <Switch>
                  <Route path="/" exact={true} component={Home} />
                  <Route path="/scores"  component={Scores} />
                  <Route path="/board" component={Board} />
                  <Route path="/about" component={About} />
                  <Route component={NoMatch} />
                </Switch>
            </div>
          </div>
        </ConnectedRouter>
      </Provider>
    );
  }
}

export default App
import multer from 'multer';

// see customize section
const upload = multer({dest:'uploads/'})

const app = express();
app.use(bodyParser.urlencoded({extended:true}));
app.use(bodyParser.json());

app.post('/contact',upload.single('profile'),(req,res)=>{
    console.log(req.file.key); // get the name of the file
    console.log(req.body); // Other fields are in req.body
    res.redirect('/');
})

// ----------------------------------
// upload options
upload.single("field-name");
upload.array("field-name");
upload.fields([
  { name: 'avatar', maxCount: 1 },
  { name: 'gallery', maxCount: 8 }
])

// ---------------------------------
// customize multer
const storage = multer.diskStorage({
    destination: function (req, file, cb) {
      cb(null, path.resolve('/uploads'));
    },
    filename: function (req, file, cb) {
      cb(null, `${file.fieldname}-${Date.now()}.${file.mimetype.split('/')[1]}`);
    }
  })
const upload = multer({storage})
import {createStore, combineReducers, compose, applyMiddleware} from "redux";

declare global {
    /* tslint:disable:interface-name */
    interface Window {
        __REDUX_DEVTOOLS_EXTENSION_COMPOSE__: any
    }
}
....

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

export default createStore<IRootState,IRootAction,{},{}>(
    rootReducer,
    composeEnhancers(
      applyMiddleware(logger)
    )
);
import React, { useEffect } from 'react'
import { Button, Form } from 'react-bootstrap'
import { useForm } from 'react-hook-form'

type FormState = {
  name: string
  color: string
  gender: string
}

export default function FormDemo() {
  const { register, handleSubmit, watch } = useForm<FormState>({
    defaultValues: {
      name: '',
      color: '#c0ffee',
      gender: '',
    },
  })

  useEffect(() => {
    let sub = watch(data => {
      console.log('update form data:', data)
    })
    return () => sub.unsubscribe()
  }, [watch])

  function submit(data: FormState) {
    console.log('submit form data:', data)
  }

  return (
    <div className="container">
      <h1>Form Demo</h1>
      <Form onSubmit={handleSubmit(submit)}>
        <Form.Group>
          <Form.Label>Name</Form.Label>
          <Form.Control type="text" {...register('name')} />
        </Form.Group>
        <Form.Group>
          <Form.Label>Color</Form.Label>
          <Form.Control
            type="color"
            {...register('color')}
            className="d-inline"
          />
          <Form.Text className="text-muted">
            Custom the background color
          </Form.Text>
        </Form.Group>
        <Form.Group>
          <Form.Label>Gender</Form.Label>
          <Form.Control as="select" custom {...register('gender')}>
            <option value="">Prefer not to say</option>
            <option>M</option>
            <option>F</option>
            <option>T</option>
            <option>Others</option>
          </Form.Control>
        </Form.Group>
        <Button variant="primary" type="submit">
          Submit
        </Button>
      </Form>
    </div>
  )
}
import React from 'react';
import { connect } from 'react-redux';
import { RootState, Item } from '../redux/state';
import { addItem, deleteItem, RootDispatch } from '../redux/action';

type Props = {
    author: string,
    items: Item[],
    handleAddItem: (newItemText: string) => void,
    handleDeleteItem: (targetId: number) => void
}
    
class TodoList extends React.Components<Props, {}> {
  constructor(props: Props) {
    super(props);
    // ...
  }
  
  // using redux dispatcher
  addItem(text: string) {
    this.props.handleAddItem(text);
  }
  
  render() {
    return (
      <>
      	<button onClick={() => this.addItem('123')}>Add item</button>
      	// using redux state
      	{this.props.items.map(item => return <p>item.name</p>)}
      </>
    )
  }
}

const mapStateToProps = (state: RootState) => {
    return {
        author: state.author,
        items: state.items
    }
}

const mapDispatchToProps = (dispatch: RootDispatch) => {
    return {
        handleAddItem: (newItemText: string) => {
            dispatch(addItem(newItemText));
        },
        handleDeleteItem: (targetId: number) => {
            dispatch(deleteItem(targetId));
        }
    }
}

export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
import { createStore }from 'redux';
import { RootAction } from './action';

import { RootState } from './state';
import { rootReducer } from './reducer';

declare global {
    /* tslint:disable:interface-name */
    interface Window {
       __REDUX_DEVTOOLS_EXTENSION__: any
    }
}

const store = createStore<RootState, RootAction, {}, {}>(
    rootReducer, 
    window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);

export default store;
import { useState } from 'react';
import { useSelector } from 'react-redux';
import { RootState } from '../redux/store';

export default function TodoList() {
  // state from redux store
  const items = useSelector((state: RootState) => state.items);
  
  // normal state
  const [nextId, setNextId] = useState<number>(0);
  
  // proceed to use state as usual
  return (
    <>
    	{items.map(item => {
         	return (
         		<TodoItem
         			text={item.name}
    			/>
         	)
        })}
    </>
  )
}
import React from 'react';

import { connect } from 'react-redux';
import { RootState } from '../redux/store';

type State = { 
  //...
}

class TodoList extends React.Components<RootState, State> {
  // rootstate is integrated into props of class component
  constructor(props: RootState) {
    super(props);
    this.state = { 
      // ... 
    }
  }
  
  render() {
    return (
      <>
      	<this.props.items>
      </>
    )
  }
}

const mapStateToProps = (state: RootState) => {
  return {
    items: state.items;
  }
}

export default connect(mapStateToProps)(TodoList);
import {createStore, Action} from "redux";


export interface IRootState{
    squares : Array<string|null>
    oIsNext: boolean
}

const initialState = {
    squares: [],
    oIsNext: true
}

const rootReducer = (state:IRootState = initialState) => {
    return {
        squares: [null,null,null,null,'O','X',null,null,null],
        oIsNext: true
    }
}

const store = createStore<IRootState,Action<any>,{},{}>(rootReducer);
export default store;

import { Provider} from 'react-redux';
import store from './store';
import Board from './Board';


class App extends React.Component {
  public render() {
    return (
      <Provider store={store}>
        <div className="game">
          <div className="game-board">
            <Board />
          </div>
          <div className="game-info">
            <div>{/* status */}</div>
            <ol>{/* TODO */}</ol>
          </div>
        </div>
      </Provider>
    );
  }
}
import '@testing-library/jest-dom'
import React from 'react';
import {render, screen} from '@testing-library/react'
yarn add bootstrap@4
//----------------------

import 'bootstrap/dist/css/bootstrap.min.css'; // Add this line
import './App.css';
npm install cors @types/cors

import cors from 'cors';
import express from 'express';

app = express();

// enable all routes
app.use(cors());

// enable single route
app.get('/route', cors(), function (req, res, next) {
  ...
})

// configure CORS
const corsOptions = {
  origin: 'http://example.com',
  optionsSuccessStatus: 200 // some legacy browsers (IE11, various SmartTVs) choke on 204
}

app.get('/route', cors(corsOptions), function (req, res, next) {
  ...
})

// enable pre-flight
app.options('/products/:id', cors()) // enable pre-flight request for DELETE request
app.del('/products/:id', cors(), function (req, res, next) {
  res.json({msg: 'This is CORS-enabled for all origins!'})
})
  
// enable pre-flight across-the-board
app.options('*', cors()) // include before other routes
import { Component, HostListener } from '@angular/core';


@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent {
  
  public getScreenWidth: any;
  public getScreenHeight: any;
  
  ngOnInit() {
      this.getScreenWidth = window.innerWidth;
      this.getScreenHeight = window.innerHeight;
  }
  
  @HostListener('window:resize', ['$event'])

  onWindowResize() {
    this.getScreenWidth = window.innerWidth;
    this.getScreenHeight = window.innerHeight;
  }
  
}
const Component = React.forwardRef<RefType, PropsType>((props, ref) => {
  return someComponent;
});
export function debounce(fn, timeout = 1000) {
  let timeoutRef = null;

  return (...args) => {
    if (timeoutRef) clearTimeout(timeoutRef);

    timeoutRef = setTimeout(() => {
      return fn(...args);
    }, timeout);
  };
}
import { useReducer } from "react";
import { debounce } from "utils";
import localStorageReducer from "./useLocalStorage.reducer";
import { _getState, _setLocalStorage } from "./useLocalStorage.utils";

export default function useLocalStorage(
  defaultKey = "default",
  defaultInitialState = {}
) {
  const [state, dispatch] = useReducer(
    localStorageReducer,
    null,
    getInitialState
  );

  function getInitialState() {
    const _state = _getState(defaultKey, defaultInitialState, {
      defaultKey,
    });

    _setLocalStorage(defaultKey, _state);

    return _state;
  }

  return [state, dispatch, defaultInitialState];
}

export function _createStorage(dispatch) {
  return (lsKey, state) => {
    dispatch({
      type: "CREATE_STORAGE",
      lsKey,
      state,
    });
  };
}

export function _updateStorageByKey(dispatch) {
  return (stateKey, state) => {
    dispatch({
      type: "UPDATE_STORAGE_BY_KEY",
      state,
      stateKey,
    });
  };
}

export function _updateStorage(dispatch) {
  return (state) => {
    dispatch({
      type: "UPDATE_STORAGE",
      state,
    });
  };
}

export function _deleteStorage(dispatch) {
  return (lsKey) => {
    dispatch({
      type: "DELETE_STORAGE",
      lsKey,
    });
  };
}

export function _updateKey(dispatch) {
  return (lsKey, stateUpdates = {}) => {
    dispatch({
      type: "UPDATE_KEY",
      lsKey,
      stateUpdates,
    });
  };
}

export function _setCurrentKey(dispatch) {
  return (lsKey) => {
    dispatch({
      type: "SET_CURRENT_KEY",
      lsKey,
    });
  };
}

import {
  _getState,
  _setLocalStorage,
  _clearLocalStorage,
  _debouncedSetLocalStorage,
} from "./useLocalStorage.utils";

export default function localStorageReducer(state, action) {
  switch (action.type) {
    case "CREATE_STORAGE": {
      const { lsKey, state: defaultState } = action;
      const { defaultKey } = state;

      const _state = _getState(lsKey, defaultState, { defaultKey });

      _setLocalStorage(lsKey, _state);

      return _state;
    }

    case "UPDATE_STORAGE": {
      const { lsKey } = state;
      const { state: _state } = action;

      const updatedState = {
        ...state,
        ..._state,
      };

      //since certain actions cause a substantial amount of rerenders per ms, it's best to defer access to local storage by debouncing
      _debouncedSetLocalStorage(lsKey, updatedState);

      return updatedState;
    }

    case "UPDATE_STORAGE_BY_KEY": {
      const { lsKey } = state;
      const { state: _state, stateKey } = action;

      const updatedState = {
        ...state,
        [stateKey]: _state,
      };

      _debouncedSetLocalStorage(lsKey, updatedState);

      return updatedState;
    }

    case "DELETE_STORAGE": {
      const { lsKey } = action;
      const { defaultKey } = state;

      if (lsKey === defaultKey) return state;

      _clearLocalStorage(lsKey);

      return _getState(defaultKey);
    }

    case "SET_CURRENT_KEY": {
      const { lsKey } = action;

      return _getState(lsKey);
    }

    //update keys in KEYS
    case "UPDATE_KEY": {
      const { stateUpdates, lsKey } = action;
      const { lsKey: lsKeyPrev, defaultKey } = state;

      if (lsKey === lsKeyPrev) return state;
      if (lsKeyPrev !== defaultKey) _clearLocalStorage(lsKeyPrev); //clear storage with previous key, unless it is the default key

      const _state = _getState(lsKey, state, { ...stateUpdates, lsKey });
      _setLocalStorage(lsKey, _state);

      return _state;
    }

    //useful for when you don't want to update the localStorage
    case "UPDATE_STATE": {
      return action.state;
    }

    default: {
      throw new Error(`Unhandled action type: ${action.type}`);
    }
  }
}


export function _getState(lsKey, defaultState, overwrites = {}) {
  const _state = _getLocalStorage(lsKey, defaultState);

  const state = { ..._state, ...overwrites, lsKey };

  return state;
}

export function _getKeys(key) {
  const _keys = Object.keys(localStorage);
  return _keys.includes(key) ? _keys : [key, ..._keys];
}

export function _getLocalStorage(key, defaultState) {
  const valueInLocalStorage = window.localStorage.getItem(key);
  return JSON.parse(valueInLocalStorage) ?? defaultState;
}

export function _setLocalStorage(key, state) {
  window.localStorage.setItem(key, JSON.stringify(state));
}

export const _debouncedSetLocalStorage = debounce(_setLocalStorage, 100);

export function _clearLocalStorage(key) {
  window.localStorage.removeItem(key);
}
export interface IViewBoxProps {
  x: number;
  y: number;
  zoom: number;
  width: number;
  height: number;
  activeNodeId?: string;
}

type TViewBoxReturn = [
  { viewBox: string; viewBoxProps: IViewBoxProps },
  (arg0: Partial<IViewBoxProps>) => void
];

export default function useViewBox(
  defaultState: IViewBoxProps
): TViewBoxReturn {
  const [viewBoxProps, _configsDispatch] = useLocalStorage(
    "_viewboxConfigs",
    defaultState
  );

  const viewBox = getViewBox(viewBoxProps);
  const updateViewBox = _updateStorage(_configsDispatch);

  return [{ viewBox, viewBoxProps }, updateViewBox];
}

function getViewBox(viewBoxProps: IViewBoxProps) {
  const { x, y, width, height, zoom } = viewBoxProps;

  const xyOffset = 2 ** -zoom;
  const _x = x - (width / 2) * xyOffset;
  const _y = y - (height / 2) * xyOffset;

  const whOffset = 2 ** zoom;
  const _w = width / whOffset;
  const _h = height / whOffset;

  return [_x, _y, _w, _h].join(" ");
}
const useElementMeasure = (
	elRef: React.RefObject<any>,
	effectDeps: unknown[] = []
) => {
	const [{ width, height }, setMeasure] = useState(() => {
		const element = elRef?.current;

		return {
			width: element ? element.clientWidth : 0,
			height: element ? element.clientHeight : 0,
		};
	});

	const measure = useCallback(() => {
		const element = elRef?.current;
		if (!element) {
			return;
		}

		setMeasure({
			width: element.clientWidth,
			height: element.clientHeight,
		});

	}, [elRef, ...effectDeps]);

	useEffect(() => {
		measure();

		window.addEventListener("resize", measure);

		return () => {
			window.removeEventListener("resize", measure);
		};
	}, [measure]);

	return [width, height];
}
var total = value.reduce((prev, next)=>{
  	return prev +(next.quantity * this.productMap(next.productId).price)
},0 )
import { Knex } from "knex";

export async function seed(knex: Knex): Promise<void> {
    await knex('students').del();
    await knex('teachers').del();

    const [teacher_id] = await knex.insert({
        name: "Bob",
        date_of_birth: "1970-01-01"
    }).into('teachers').returning('id');

    return await knex.insert([{
        name: "Peter",
        level: 25,
        date_of_birth: "1995-05-15",
        teacher_id: teacher_id
    },{
        name:"John",
        level: 25,
        date_of_birth: "1985-06-16",
        teacher_id: teacher_id
    },{
        name:"Simon",
        level: 25,
        date_of_birth: "1987-07-17",
        teacher_id: null
    }
    ]).into('students');
};
yarn knex  seed:make -x ts create-teachers-and-students
export async function up(knex: Knex) {
    if(await knex.schema.hasTable('teachers')){
        await knex.schema.alterTable('teachers',(table)=>{
            table.renameColumn("name","teacher_name");
            table.decimal("level",3).alter();
        });  
    }
};

export async function down(knex: Knex) {
    if(await knex.schema.hasTable("teachers")){
        await knex.schema.alterTable('teachers',(table)=>{
            table.renameColumn("teacher_name","name");
            table.string("level").alter();
        });
    }
};
yarn knex migrate:make create-memos
import { Knex } from "knex";

export async function up(knex: Knex)  {
    if(!await knex.schema.hasTable("students")){
        await knex.schema.createTable("students",(table)=>{
            table.increments();
            table.string("name");
            table.string("level");
            table.date("date_of_birth");
            table.integer("teacher_id").unsigned();
            table.foreign('teacher_id').references('teachers.id');
            table.timestamps(false,true);
        });
    }
};

export async function down(knex: Knex){
    await knex.schema.dropTableIfExists("students");
};
import dotenv from 'dotenv';
dotenv.config();

module.exports = {

  development: {
    debug: true,
    client: "pg",
    connection: {
      database: process.env.DB_NAME,
      user: process.env.DB_USERNAME,
      password: process.env.DB_PASSWORD
    },
    pool: {
      min: 2,
      max: 10
    },
    migrations: {
      tableName: "knex_migrations"
    }
  },

  staging: {
    client: "pg",
    connection: {
      database: process.env.DB_NAME,
      user: process.env.DB_USERNAME,
      password: process.env.DB_PASSWORD
    },
    pool: {
      min: 2,
      max: 10
    },
    migrations: {
      tableName: "knex_migrations"
    }
  },

  production: {
    client: "pg",
    connection: {
      database: "my_db",
      user: "username",
      password: "password"
    },
    pool: {
      min: 2,
      max: 10
    },
    migrations: {
      tableName: "knex_migrations"
    }
  }

};
yarn add knex @types/knex pg @types/pg
yarn knex init -x ts
yarn add dotenv @types/dotenv
{
    "sqltools.connections": [
        {
            "previewLimit": 50,
            "server": "localhost",
            "port": 5432,
            "driver": "PostgreSQL",
            "name": "memo_wall",
            "database": "memo_wall",
            "username": "junowong",
            "password": "gfHK$dgm6501"
        }
    ]
}
test('adds 1 + 2 to equal 3', () => {
    expect(sum(1, 2)).toBe(3);
});

test('object assignment', () => {
  const data = {one: 1};
  data['two'] = 2;
  expect(data).toEqual({one: 1, two: 2});
});

`toBeNull matches only null
toBeUndefined matches only undefined
toBeDefined is the opposite of toBeUndefined
toBeTruthy matches anything that an if statement treats as true
toBeFalsy matches anything that an if statement treats as false`
yarn add --dev jest
yarn add --dev typescript ts-jest @types/jest @types/node ts-node ts-node-dev
yarn ts-jest config:init
import {Client} from 'pg';
import dotenv from 'dotenv';
dotenv.config();

export const client = new Client({
    database: process.env.DB_NAME,
    user: process.env.DB_USERNAME,
    password: process.env.DB_PASSWORD
});

client.connect();

/--------.env file ------------/
DB_NAME=memo-wall
DB_USERNAME=gordon
DB_PASSWORD=gordon
let sessionMiddleware = expressSession({
  secret: 'Tecky Academy teaches typescript',
  resave: true,
  saveUninitialized: true,
});

app.use(sessionMiddleware);

io.use((socket, next) => {
  let req = socket.request as express.Request;
  let res = req.res!;
  sessionMiddleware(req, res, next as express.NextFunction);
});

io.on('connection', function (socket) {
    if(!socket.request.session.user){
        socket.disconnect()
    }
});
async function logout(req:express.Request,res:express.Response){
    if(req.session){
        delete req.session['user'];
    }
    res.redirect('/login.html');
}
import {Request,Response,NextFunction} from 'express';

export function isLoggedIn(req:Request,res:Response,next:NextFunction){
    if(req.session?.['user']){
        next();
    }else{
        res.redirect('/login.html');
    }
}
app.post('/apple',(req,res)=>{
    // logic of adding apple.
    if(req.session){
        io.to(`user-${req.session['user'].id}`).emit("new-apple","Congratulations! New Apple Created!");
    }
    res.json({updated:1});
});

io.on('connection', function (socket) {
    ....
    if(socket.request.session['user']){
        socket.join(`user-${socket.request.session['user'].id}`);  
        // One common way is to join the socket to a room named by the `user.id` or other group information.
     }
});
import expressSession from 'express-session';
const app = express();

// Add this line
app.use(expressSession({
    secret: 'Tecky Academy teaches typescript',
    resave:true,
    saveUninitialized:true
}));
const sessionMiddleware = expressSession({
    secret: 'Tecky Academy teaches typescript',
    resave:true,
    saveUninitialized:true,
    cookie:{secure:false}
});

app.use(sessionMiddleware);

io.use((socket,next)=>{
    let req = socket.request as express.Request
    let res = req.res as express.Response
    sessionMiddleware(req, res, next as express.NextFunction
});
//...
io.on('connection', function (socket) {
    // You can set any values you want to session here.
    const req = socket.request as express.Request;
    req.session['key'] = 'XXX';
    // There is no auto save for session.
    socket.request.session.save();

    // You can also send data using socket.emit() although it is not very useful
    socket.emit('any-key','values');
    socket.on("disconnect",()=>{
        //... rest of the code
    })
});
import {Request,Response} from 'express';
import express from 'express';

const app = express();
app.use(express.urlencoded({extended:true}));
app.use(express.json());
{
    "compilerOptions": {
        "module": "commonjs",
        "target": "es5",
        "lib": ["es6", "dom"],
        "sourceMap": true,
        "allowJs": true,
        "jsx": "react",
        "esModuleInterop":true,
        "moduleResolution": "node",
        "noImplicitReturns": true,
        "noImplicitThis": true,
        "noImplicitAny": true,
        "strictNullChecks": true,
        "suppressImplicitAnyIndexErrors": true,
        "noUnusedLocals": true
    },
    "exclude": [
        "node_modules",
        "build",
        "scripts",
        "index.js"
    ]
}
import expressSession from 'express-session';
const app = express();

// Add this line
app.use(expressSession({
    secret: 'Tecky Academy teaches typescript',
    resave:true,
    saveUninitialized:true
}));
import express from 'express';
import {Request,Response} from 'express';

const app = express();

app.get('/',function(req:Request,res:Response){
    res.end("Hello World");
})

const PORT = 8080;

app.listen(PORT, () => {
    console.log(`Listening at http://localhost:${PORT}/`);
});
import express from 'express';
import http from 'http';
import {Server as SocketIO} from 'socket.io';

//....
const app = express();
const server = new http.Server(app);
const io = new SocketIO(server);

io.on('connection', function (socket) {
    console.log(socket);
});
//....
const PORT = 8080;
server.listen(PORT, () => {
    console.log(`Listening at http://localhost:${PORT}/`);
});
import { useSelector, TypedUseSelectorHook } from "react-redux";
// Import type of state 
// Import {RootState} from '../store'

export const useTypedSelector: TypedUseSelectorHook<RootState> = useSelector;
{
  "editor.formatOnSave": true,
  "typescript.tsdk": "./node_modules/typescript/lib",
  "eslint.format.enable": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  }
}
const { scrollTop, offsetHeight } = document.documentElement;
const { innerHeight } = window;
const bottomOfWindow = Math.round(scrollTop) + innerHeight === offsetHeight;

if (bottomOfWindow) {
  console.log('Bottom of window');
}
    private resetTheForm(form: FormGroup): void {
      const elements = Object.values(form.controls);
      elements.forEach(element => {
        if (element instanceof FormControl) {
          element.reset();
        } else if (element instanceof FormGroup) {
          this.resetTheForm(element);
        }
      });
    }
   /*
    --------------------------
   */
    ** Pending **
  -Methods:
call(), apply(), bind()



  **

  Book :> The Principle of Object oriented Javscript

    **
   : Dereferencing Objects //Is used to Clear the memory on browser           engine.
var object1 = new Object();
// do something
object1 = null;
    // dereference  
   **
    
    **
    : Deleting a value from Object.
    > delete objName.key;
    **
      
    **
    : Function Example -
  function reflect(value) {
    return value;
  }
// is the same as
var reflect = new Function("value", "return value;"); 
     **
        
      **
  arrName['push']('3'); //This is also valid ( using bracket              notation )
       **

      ** // It will store the values as an Object ( String ).
  let nameVariable = new String();
nameVariable.fname = 'Karan';
nameVariable.lname = 'Singh';
       **
           
       ** hasOwnProperty **
    let obj = { fname: "Karan", lname: "Singh" }

    > console.log('fname' in obj)  //true
    > console.log('lname' in obj) //true

    > console.log('toString' in obj)  //true 
    // ( Inbuilt methods will also return true )

    > console.log(obj.hasOwnProperty('toString')) //False
    **
           
       **
           //Ways to access Properties in Object
         > Object.keys(objName); //Will return keys
         > Object.values(objName); //Will return values 
  
       **
       //To check if Properties are Enumerable                                                (propertyIsEnumerable).
    > (objName.propertyIsEnumerable(key)); //true or false

      Object.defineProperty(obj, prop, descriptor) //Syntax
       **
        //We can change the default state of the Object.

        var person1 = {};
       **
      Object.defineProperty(person1, "name", {
        value: "Nicholas",
        enumerable: true,
        configurable: true,
        writable: true
      }); //It will create 'name' in person1 Object with 'descriptor'.

      Object.defineProperty(person1, "name", {
      enumerable: false
      }); //We can define in Single Lines as well ( Depending upon our need )

      Object.defineProperty(person1, 'property1', {
        value: 42,
        writable: false
      });// 'property1' can not be overwritten.


      **
     //Preventing Object Modification      
       //Syntax
      > Object.preventExtensions(person1); //false
            /*It will not allow to add new properties to object 'person1'.
            */
      //isExtensible() (How to check?)
      > console.log(Object.isExtensible(obj)); //It will tell whether it's               extensible or not ( true / false )

**
       //Freezing the Object. ( Cant not add/remove. ( read-only ) )
        > Object.feeze(objName);

        //isFrozen() ( How to Check? )
       > console.log(Object.isFrozen(objName)); //Will return true or false.


   ** //Three methods which does not allow mathods to add/remove properties.
        > Object.preventExtensions(objName)
        > Object.seal(objName)
        > Object.freeze(objName)
        //To how to check, Use these methods.   
        console.log(Object.isExtensible(person1));
        console.log(Object.isSealed(person1));
        console.log(Object.isFrozen(person1));



     **//Using Prototypes with Constructors

          function Person(name){
            this.name = name;
          }

          Person.prototype.sayName = function(){
            return this.name;
          }

          let karan = new Person("Jaskaran");













/*
 ---------------------------------------------------------------------
*/
--------------------
                                //Number


Number.isNaN(24);
// False.

let number1 = -Infinity;
let number2 = Infinity;  
--------------------
                                   //String


String(77).padStart(6,0);
// 000077


let str = 'Jaskaran Singh Pannu';
str.repeat(10)

console.log("Karan- ".repeat(4));
//Karan- Karan- Karan- Karan-
-------------------
-------------------

-------------------
                                   //Object
  
  
let {name , age} = {name: "Faraji", age: 23};
console.log(name , age);
// → Faraji , 23


let obj = { name  : 'karan' };
consol.log( 'name' in obj);
//true;

     // Prototype ( Just to check if the certain properties are there.
Object.prototype.addNewMethod = function(){ return "Yeah"};
console.log('addNewMethod' in Object);
//true;
console.log('toString' in Object);
//true;

 //hasOwnProperty  ( It will just show the 'obj's properties ( code written ) , Not of it's parent ( Object).
let obj = { name : 'karan' };
obj.hasOwnProperty("name");
//true;
obj.hasOwnProperty('toString');
//False;

 //Get  // Set //Statics.
let obj = {
  //keyword 'get'
  get powerOne(){ return "Power 1" },
  powerTwo : function(){
    return "Power2, Old School."
  }
};
obj.powerOne;
// OR. (The Only difference is, If we are using keyword "get", We don't have to use "()" while calling any function.
obj.powerTwo();
------------------------
                                //Classes
class basics{
  constructor( name  ){
     this.name = name;
  }
  skillOne(skill){
    return this.name + " is " + skill
  }
}

class ChildOne extends basics{
  constructor( name , age , country ){
    super( name )
    this.age = age;
    this.country = country;
  }
  skillTwo(){
    return " Skill Two here... "
  }
}
----------------------
//instanceof
let arr = {};
console.log(arr instanceof Object)
// true.
let arr2 = []
console.log(arr2 instaceof Object);
// true ( Object is main base for all the non-primitives data types ( functions / arrays ).
------------------------
//Object.freeze
let object = Object.freeze({value: 5});
object.value = 10;
console.log(object.value);
// → 5
-----------------------
                               //HOF
  //Data.
const companies = [
  {name: "Company One", category: "Finance", start: 1981, end: 2005},
  {name: "Company Two", category: "Retail", start: 1992, end: 2008},
  {name: "Company Three", category: "Auto", start: 1999, end: 2007},
  {name: "Company Four", category: "Retail", start: 1989, end: 2010},
  {name: "Company Five", category: "Technology", start: 2009, end: 2014},
  {name: "Company Six", category: "Finance", start: 1987, end: 2010},
  {name: "Company Seven", category: "Auto", start: 1986, end: 1996},
  {name: "Company Eight", category: "Technology", start: 2011, end: 2016},
  {name: "Company Nine", category: "Retail", start: 1981, end: 1989}
];
const ages = [  10, 0,10, 40, 50 , 88, 9 , 20 ,89, 100 ,6];


//Sort
let sort = ages.sort((a , b ) => a - b );
sort = companies.sort( (a , b ) =>  a.start -b.start    )

//Reduce , Suming the Arrays.
let totatAges = ages.reduce(( total, item )=> total + item, 0 );
let totalYears = companies.reduce(( total , item ) => total + (item.end - item.start)
,0)

let out = nums.reduce(( firstItem , singleItem ) => {
 let max = firstItem > singleItem ? firstItem : singleItem;
 return max; 
})


// There is another method called => "Find" 

                        /* "Every" */ ( it return boolean value ) 
//It will test whether all elements in the array pass the provided function.
let output = students.every((item)=>{
  return item.grade >= 100;
})

                       /* "SOME"  */  ( it return boolean value )
//Similar to every, but returns true if ANY of the array elements pass the test function
let output = students.some((item)=>{
  return item.grade >= 100;
})



//Combined
let combined = ages
                   .sort((a,b) => a-b)
                   .filter( item => item <= 10 )
                   .map( item => item * 1 ) 
                   .reduce( (total,item)=> total + item ,0 );

//Destructing 
//Objects example
let  {name, age, ...evrythingElse} = {  name : 'Jaskaran',  age : 34, country : "U.S", cool : true }
console.log(name); //Jaskaran
console.log(age); //34
console.log(evrythingElse); // { country:'U.S', cool: true }

//Array Example
let arr = ["Jaskaran","Singh","Pannu"];
let  [firstName, ...everythingElse ]  = arr;
console.log(everythingElse); // ['Singh', 'Pannu']


//Param Destructing
let fullName = ({fN, lN }) =>{ return fN + " " + lN }

let objName = {
  fN : "Karan",
  lN :"Singh"
}

fullName(objName);



/* Async */


//1 way.
fetch("https://icanhazdadjoke.com/slack").then((res)=>{
        res.json().then((data)=>{
        console.log(data)
    })
});

//2nd Way
let link = "https://icanhazdadjoke.com/slack";
let xhr = new XMLHttpRequest();

xhr.open('GET',link, true);
xhr.send();

xhr.onreadystatechange = function(){
if(xhr.readyState == 4){
    console.log(xhr.responseText);
 }
}


typeof
type guards
As we’ve seen, JavaScript supports a typeof operator which can give very basic information about the type of values we have at runtime. TypeScript expects this to return a certain set of strings:

"string"
"number"
"bigint"
"boolean"
"symbol"
"undefined"
"object"
"function"
const extraInformationInput = new FormControl();

 this.extraInformationForm = new FormGroup({
      extraInformation: extraInformationInput,
    });

this.extraInformationForm.valueChanges.subscribe(
  change => {
    console.log('change triggered -> ', change);
  }
);
    
// By Maxi.

//Installing Bootstrap ( locally )
 > npm install bootstrap@3 --save


// Data Binding.
..> Output Data
/* 
1.String Interpolation :
Should be a string, Or can be converted to string.
*/
 <h3>My Name is {{ name }}  {{'Singh'}}   {{ lastName() }} </h3> 

/*
2. Property Binding :
*/
  ( [propert] ='data' )

.HTML
<button class="btn btn-primary" [disabled]="!allowNewServer">Click here</button> <b [innerText] = "allowNewServer">  </b>

.TS
  setTimeout(()=>{ this.allowNewServer = true;
  },2000)
// 'disabled' is the property here, We are toggling the boolean value to disable or enabled the between ( if it's true then it will be disabled else btn will be enabled. )


..< React to Events
 ( (event) = 'expression' )

/*
3. Two way Binding : 
*/
  ( [(ng Model)] = 'data' )
/* 
> Commands for npmp pack or Terminal.
*/

// Install Cmd ( Globally ).
npm install-g typescript  

//Adding Bootstrap.
npm install bootstrap --save



-----------------------------------------------------------


//Typescript
//Data types
string
number
boolean
string
string[]   //Array of Strings
number[]   //Array of Numbers
any[]      //Array of any Data type
undefined  //undefined
void       //undefined   or if the value won't be returned ( void ( khaali ) )
enum
any

let canBeOneOfTheseTwoType : string | boolean;  // The value can be "string" or "boolean".
let data : number | boolean | string = '980033' ; // Valyue can be 1/3 data types.
let data2 : any = "Jaskaran"; //Any type of data type can used. 

let mixArray:[string, number, string, boolean] = ["Jaskaran", 1996, "Singh", true]; //Structure has to be same.

enum Color {Red, Green, Blue};
let data: Color = Color.Red;   //Will return 0 
let data2: Color = Color.Blue; // Will return 2

//Default Parameter.
function check(a:string, b:string = '99'):string{
    return "Default Parameter"
}

//Optional Parameter.
function check(a:string, b? :string ):string{
    return " b is optional here "
}

//Having multiple data types and optional argument.
function check(n1: number | boolean , n2? :number | string) { 
  return "Optional Paramter and multiple Data types"
}

//Interface
interface IAPIResponse {
    name : string,
    age : number
}

function playerOne(): IAPIResponse {
    return {
        name : 'Jaskaran',
        age : 20
    }
}

function playerTwo(): IAPIResponse {
    return {
        name : "Karan",
        age : 26
    }
}

console.log(playerOne());
console.log( playerTwo());




             /*  --------------- Class 1 ------------------ */




//CMD commands for TSC.
-h, -help
-w, -watch
--pretty
--all
-v, --version
--init    // Initialize
-p, --project
-b, --build
-t, --target
-m, --module

//To Change from TS to JS.
tsc index.ts //It will output the new file in the same directory with "index.js"


       /*   --------------------  Class 2  ------------------------- */

// Module and Component
 
 module1
    ->component1-1
    ->component1-2
    ->component1-3
    ->component1-4

 module2
    ->component2-1
    ->component2-2
    ->component2-3
    ->component2-4

 module3
    ->component3-1
    ->component3-2
    ->component3-3
    ->component3-4
  // Components are small parts of module. And App is divided into multiple modules(  Parent )

Component:
    M : Data ( will control V & C )
    V : template ( .html )
    C : logic  ( .ts )


//Meta Data
@NgModule {   //@NgModular is called decorator
  //I s Module
}
export class{}

@Component {    //@Component is called decorator
  //Is a Component 
}
export class{}

@Injectable {   //@Injectable is called decorator
  //Is a Service
}
export class{}


//On Start
   1. main.ts --> App Module
   2. App Module --> 
     
     
 // Inserting as component    //Default set up.
<div app-products></div>  
@Component({
  selector: '[app-products]'
 }
           
//Inserting as a Class
<div class="app-products"></div>           
@Component({
  selector: '.app-products'
}



    /*   --------------------  Class 3  ------------------------- */ "{}" is a Class.

//Event Binding:
// .html
<button (click) ="willDoSomething();"></button>   //DOM to component.
//.ts

--------------------------------------
/*
 1. Property Binding:
//#CASE ( Passing the values/data from parent Component "App" to child component"Header" )
( PARENT ), 
*/
>app.module.ts
import { FormsModule } from '@angular/forms';
imports: [
  FormsModule
]

  {
     list = [
    { Name: "nike", Product: "Shoes" },
    { Name: "Apple", Product: "Phones" },
    { Name: "BB", Product: "Software" },
    { Name: "Samsung", Product: "Chips" },
  ]
 }

----------------------------

 >app.html
  <app-header [productsOne]="list"></app-header>
-------------------------
>header.html
    <tr *ngFor='let item of productsOne'>
      <td> {{item.Name}} </td>
      <td>  {{ item.Product }} </td>
    </tr>
-------------------------
 >header.ts
import {  Input } from '@angular/core';
{
  @Input()
  productsOne: any;
}

                            --------------------------

//#CASE ( Passing the values/data from Child Component "Header" to Parent component"App" )
/*
Event Binding:
*/
>header.html
<button class="btn" (click)="childButtonClicked();">ChildButton</button>
--------------------------------                                    
>header.ts
import {  Output, EventEmitter } from '@angular/core';
 {
     constructor() { 
     this.dataOne = new EventEmitter();
     }
   
     @Output()
     dataOne: EventEmitter<any>;

     childButtonClicked(){
         this.dataOne.emit({
           name : "Karan",
           age : "25"
         }); 
 }
--------------------------------

>app.html
<app-header (dataOne)="dataComingFromChild($event);" ></app-header>
   
---------------------------------
>app.ts                                    
  dataComingFromChild(data:any){
    console.log(data);
  }
-----------------------------------
  
To flow data one direction.
[ngModel] ='val' ; 

 To flow data both the direction.
[(ngModel)] ='val' ;  ( value will be binded )

   
     /* Directives
      1. Components as directives (simple/single component)
      2. Structural Directives
        ngIf
        [hidden]
        ngFor
        ngSwitch
      3. Attribute Directives
       [ngStyle]
       [ngClass]
      4. Custom Directives
      
     
     */
   
// Structural Directives:   
   
   /*
    ngIf
    [hidden]
    ngFor
    ngSwitch
   */
   
"*ngFor" is known as structure directive, As it changes the structure of the web page.   

//ngIF - Structural directive
<div *ngIf='condition'>
  Content will Render if condition is true
</div>
   
//ngClass   
 /*
 Add or Remove CSS classes ( using Logic )
 */

 /*   --------------------  Class 4  ------------------ */
//*ngIf
>> #Case   
header.html
<div>
  <div *ngIf="defaultBool">
    Data is in the First Slot
  </div> 
  <div *ngIf="!defaultBool">
    Data is in the Second Slot
  </div> 
 
  <button class="btn btn-block" (click)='toggleData()'>
    Click to Toggle
  </button>
 </div>
   
header.ts   
  defaultBool:boolean = true;
  toggleData(){
    this.defaultBool = !this.defaultBool;
  }
      ----------------------------------------------------
//Else-if   
 #case  
>header.html   
  <div *ngIf="defaultBool else toggleIDName">
    Data is in the First Slot
  </div> 

 <ng-template #toggleIDName>
  <div>
    Data is in the Second Slot
  </div> 
 </ng-template>
 
  <button class="btn btn-block" (click)='toggleData()'>
    Click to Toggle
  </button>   
   
> header.ts   
  defaultBool:boolean = true;
  toggleData(){
    this.defaultBool = !this.defaultBool;
  }
       ----------------------------------------------------
//[hidden] property: ( mostly used for Small parts )
   
.html
<div [hidden]='defaultHiddenValue'>
 Hidden Example </div>  	 
<button (click)="toggleHidden"> Click to hide </button>
   
.ts
   defaultHiddenValue:boolean = true;
   toggleHidden(){
     this.defaultHiddenValue = !this.defaultHiddenValue;
   } 
  
** The Hidden property will hide the stuff from the web page( Will be visible in Source Code ), Where as 'NgiF' will completely remove/add the Elements/element from DOM,   
      ----------------------------------------------------
// Ngswitch
  #syntax:
 <div [ngSwitch]='companiesList'>
      <p *ngSwitchCae="aws">AWS stuff </p>
      <p *ngSwitchCae="google">google stuff </p>
      <p *ngSwitchCae="MS">MS stuff </p>
      <p *ngSwitchCae="Applce">Applce stuff </p>
      <p *ngSwitchDefault="Defaul Value"> kites </p>
  </div>
   
 
.html
  <div [ngSwitch]='selectCourse'>
    <div *ngSwitchCase="'react'">react</div>
    <div *ngSwitchCase="'angular'">angular</div>
    <div *ngSwitchCase="'vue'">vue</div>
    <div *ngSwitchDefault> Default value..... </div>
  </div>   
<button (click)="reactCourse()">React Developer </button>
<button (click)="angularCourse()">Angular Dev </button>
<button (click)="vueCourse()">Vue Developer </button>  
   
.ts
   {
    selectCourse:string = '';

    reactCourse(){ this.selectCourse = "React"; }
    angularCourse(){ this.selectCourse = "Angular"; }
    vueCourse(){ this.selectCourse = "Vue"; }     
     }
   
      ----------------------------------------------------
      
 //Attribute Directives
      /*
      [ngStyle]
      [ngClass]
      */
      
      
// ngStyle: 
.html
<h1 [ngStyle]= "{ 'color' : selectedColorName }">
 "Some Text here";
</h1>
<button (click)="redColor()"> click to red it </button>
.ts
selectedColorName:string = 'gray'; //By default the color will be gray. 

 redColor(){
   this.selectedColorName = 'red';
 }  
 //We can change the color value dynamically as per our need.
   
   ----------------------------------------------------
// ngClass : attribute Directive.    
.html
  <h2 [ngClass] = "{ 'className1' : variableName == 'average', 'className2' : variableName == 'good' }" >
   {{ selectCourse }} :  {{variableName}}   // Will manipulate the classes depending upon 'variableName' value.
  </h2>

.ts
  variableName:string = "average"; //Default value.
//We can change the variableName value dynamically as per our need, To 'average' or 'good' or anything and then set that value in HTML attribute value. 
 
   ----------------------------------------------------
   /*
 //Custom directives   
    :When inbuilt directives are not sufficient, We create       our own directives as per our need. 
    
     #syntax: 
     @Directive()  //decorator
     class myDirectiveName {
       //class
     }
   */
   
   > ng g directive myCustomDirectiveName //CLI

customDirective.ts
import { ElementRef, HostListener } from '@angular/core';

  constructor( private eleRef: ElementRef ) { 
   }
   @HostListener('mouseenter') onEnter() {
     this.eleRef.nativeElement.style.background = 'gray';
     this.eleRef.nativeElement.style.cursor = 'pointer';
   }
   @HostListener('mouseleave') onLeave(){
    this.eleRef.nativeElement.style.background = 'initial';
   }

header.html
  <div>
    <ol>
      <li appMyCustomDirective>Nike</li>
      <li appMyCustomDirective>UA</li>
      <li appMyCustomDirective>Roots</li>
    </ol> 
  </div>
   
   

  /*
                     PIPES
   : PIPEs are used to improve/increase the functionaility of the     app/page.
   
   Types:
   1.Inbuilt Pipes
   2.Custom Pipes.
  */

1.Inbuilt Pipes
#example 
> header.ts

dob = new Date();
price = 10;
name = 'jaskaran'
 
 > header.html

  <ol>
 <li> {{ name | uppercase }} </li>
 <li> {{ name | lowercase }} </li>
 <li> {{ name | titlecase }} </li>
  </ol> 

  <div> 
    Short date formate: {{ dob | date: 'short' }}   <br>
    Full date formate: {{ dob | date: 'full' }}    <br>
    Custom Format1: {{ dob | date: 'MM/dd/YYYY' }} <br>
    Custom Format2: {{ dob | date: 'dd-MM-YYYY' }} <br>
  </div>

 <div>
   currencyDollar (default) :  {{ price | currency }}  <br>
   currency Pound :  {{ price | currency:'GBP' }}  <br>
   currency Rupee :  {{ price | currency :'INR' }}  <br>
 </div>

> 2.Custom Pipes.
 - cli
 ng g pipe customPipeName

#syntax: ( CLI will automatically generate the structure for us. )

 @Pipe()
 export class customPipeName{
 }

#Example 1.
.custom.pipe.ts
export class CustomPipePipe implements PipeTransform {
  transform(value: string ): string {
    return value + "-Extra String..........";
 //value is the "actual" item to work on.
  }
}

header.html
 {{ 'Jaskaran' | customPipe }}
   //Output will 'Jaskaran-Extra String..........' 

#Example 2.
> footer.ts
  list = [
    { Name: "nike", grade: "A" },
    { Name: "Apple", grade: "B" },
    { Name: "Samsung", grade: "A" },
  ]

> gradingPipe.ts
  transform(value:any, ...args: any[]): any {
    //Value will be the complete data ( "list" ).
     //args will be values provided'Arguments' ( right side of pipe name in HTML ),
    const grade = args[0];
    const filteredStudents = value.filter(( item:any )=>{
      return (item.grade == grade);
    })
    return filteredStudents;
  }

> footer.html
 <tbody>
   <tr *ngFor="let item of list  | filterGrades:'A' ">
         <td> {{ item.Name | uppercase }}  </td>
       <td>       {{ item.grade}}  </td>
   </tr>
 </tbody>


//Services
    :Is used to share the data and the logic between different components. 

     /*   --------------------  Class 5  ---------------- */
   
   
     
    
    
     /* --------------------  Class 6  ------------------ */



     
function removeItem<T>(arr: Array<T>, value: T): Array<T> { 
  const index = arr.indexOf(value);
  if (index > -1) {
    arr.splice(index, 1);
  }
  return arr;
}
enum Colors {
  'black',
  'brown',
  'red',
  'orange',
  'yellow',
  'green',
  'blue',
  'violet',
  'grey',
  'white'
}

function EnumKeys<T>(enumType: T): (keyof T)[] {
  return (Object.keys(enumType) as Array<keyof T>)
      .filter(value => isNaN(Number(value)) !== false);
}

export const COLORS = EnumKeys(Colors)
// COLORS = ['black','brown','red','orange','yellow','green','blue','violet','grey','white']
type FooFilter<T> = { type: 'Foo', foo: T }
type BarFilter<T> = { type: 'Bar', bar: T }
type Filter = FooFilter<unknown> | BarFilter<unknown>
type FilterShapeBase = [string, Filter][]

type ValueOf<F extends Filter> = 
F extends FooFilter<infer T> ? T
: F extends BarFilter<infer T> ? T
: never

type FilterValues<FilterShape extends FilterShapeBase> = FilterShape extends Array<infer U>
    ? U extends [infer K, infer F] 
        ? K extends string
            ? F extends Filter
                ? { [Key in K]: ValueOf<F> }
                : never
            : never
        : never
    : never

function f<FilterShape extends FilterShapeBase>(filters: FilterShape): FilterValues<FilterShape> {
    const tuples = filters.map(([key, filter]) => filter.type === 'Foo' ? [key, filter.foo] : [key, filter.bar])
    return Object.fromEntries(tuples)
}

/*
HOW TO CONFIGURE THE FILTER FilterShape:

type FilterShape = [
  ['foo_in', StringSearchFilter],
  ['bar_equals', EnumSelectOneFilter<MyEnum>]
]

const filters = [
  ['foo_in', { ... }],
  ['bar_equals', { ... }],
]
*/
  constructor() {
    this.hotelForm = new FormGroup({
      name: new FormControl('', [
        Validators.required,
        Validators.minLength(5),
        Validators.maxLength(30),
      ]),
      city: new FormControl('', [
        Validators.required,
        Validators.pattern(/^[a-zA-Z áÁÍíéőöüéűŐÉÖÜ]{5,30}$/),
      ]),
      category: new FormControl('', Validators.required),
    });
  }

  ngOnInit(): void {}

  saveHotel(): any {
    const submittedHotel = this.hotelForm.value;
    console.log(submittedHotel);

    return submittedHotel;
  }
}
<section class="table-holder">
  <button id="get-button" (click)="getPostList()">Get Blog List</button>
  <table>
    <thead>
      <tr>
        <th>Title</th>
        <th>Text</th>
        <th>Category</th>
        <th></th>
      </tr>
    </thead>
    <tbody>
      <tr class="table-row" *ngFor="let post of blogPosts; let i = index">
        <td>{{ post.title }}</td>
        <td>{{ post.text }}</td>
        <td>{{ post.category }}</td>
        <td>
          <button id="delete-button" (click)="deletePost(post.id)">Delete</button>
        </td>
      </tr>
    </tbody>
  </table>
</section>
html, body, div, span, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
abbr, address, cite, code,
del, dfn, em, img, ins, kbd, q, samp,
small, strong, sub, sup, var,
b, i,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, figcaption, figure, 
footer, header, hgroup, menu, nav, section, summary,
time, mark, audio, video {
    margin:0;
    padding:0;
    border:0;
    outline:0;
    font-size:100%;
    vertical-align:baseline;
    background:transparent;
}

body {
    line-height:1;
}

article,aside,details,figcaption,figure,
footer,header,hgroup,menu,nav,section { 
    display:block;
}

nav ul {
    list-style:none;
}

blockquote, q {
    quotes:none;
}

blockquote:before, blockquote:after,
q:before, q:after {
    content:’’;
    content:none;
}

a {
    margin:0;
    padding:0;
    font-size:100%;
    vertical-align:baseline;
    background:transparent;
}

/* change colours to suit your needs */
ins {
    background-color:#ff9;
    color:#000;
    text-decoration:none;
}

/* change colours to suit your needs */
mark {
    background-color:#ff9;
    color:#000; 
    font-style:italic;
    font-weight:bold;
}

del {
    text-decoration: line-through;
}

abbr[title], dfn[title] {
    border-bottom:1px dotted;
    cursor:help;
}

table {
    border-collapse:collapse;
    border-spacing:0;
}

/* change border colour to suit your needs */
hr {
    display:block;
    height:1px;
    border:0;   
    border-top:1px solid #cccccc;
    margin:1em 0;
    padding:0;
}

input, select {
    vertical-align:middle;
}
  const target = useRef<HTMLDivElement>(null);

  const listenScrollEvent = (event) => {
    const toLeft = event.deltaY < 0 && target.current.scrollLeft > 0;
    const toRight =
      event.deltaY > 0 &&
      target.current.scrollLeft <
        target.current.scrollWidth - target.current.clientWidth;

    if (toLeft || toRight) {
      event.preventDefault();
      event.stopPropagation();

      target.current.scrollLeft += event.deltaY;
    }
  };

  return (
    <div ref={target} onWheel={listenScrollEvent}>
const IMAGE = ['jpg', 'jpeg', 'jpe', 'tiff', 'tif', 'png', 'bmp', 'gif', 'webp', 'svg', 'ai', 'psd', 'cdr', 'eps', 'ico'];
    const AUDIO = ['aif', 'cda', 'mid', 'mp3', 'mpa', 'ogg', 'wav', 'wma', 'wpl'];
    const ARCHIVE = ['7z', 'arj', 'deb', 'pkg', 'rar', 'rpm', 'tar', 'z', 'zip'];
    const EMAIL = ['email', 'eml', 'emlx', 'msg', 'oft', 'ost', 'pst', 'vcf'];
    const WEBSITE = ['asp', 'cer', 'cfm', 'cgi', 'pl', 'css', 'htm', 'html', 'js', 'jsp', 'part', 'php', 'rss', 'xhtml'];
    const DOCUMENT = [
        'key',
        'odp',
        'pps',
        'ppt',
        'pptx',
        'ods',
        'xls',
        'xlsm',
        'xlsx',
        'doc',
        'docx',
        'odt',
        'pdf',
        'rtf',
        'tex',
        'txt',
        'wpd',
    ];
import { Directive, ElementRef, HostBinding, HostListener } from "@angular/core";

@Directive({
    selector: '[appDropdown]'
})

export class DropdownDirective {
@HostBinding('class.open') isActive = false;

@HostListener('document:click', ['$event']) onClick(event: Event) {
        this.isActive = this.elRef.nativeElement.contains(event.target) ? !this.isActive : false;
    }

    constructor(private elRef: ElementRef) {}
}
import { Directive, ElementRef, Renderer } from '@angular/core';

@Directive({
    selector: '[appChbgcolor]'
})
export class ChangeBgColorDirective {

    constructor(private el: ElementRef, private renderer: Renderer) {
        this.ChangeBgColor('red');
    }

    ChangeBgColor(color: string) {

        this.renderer.setElementStyle(this.el.nativeElement, 'color', color);
    }
}
// Get path to resource on disk
 const onDiskPath = vscode.Uri.file( 
   path.join(context.extensionPath, 'css', 'style.css')
);
// And get the special URI to use with the webview
const cssURI = panel.webview.asWebviewUri(onDiskPath);
const { createCanvas, loadImage } = require("canvas");
const canvas = createCanvas(200, 200);

//TODO: replace with initials extraction logic.
var initials = "MM";

// Create a rectangular canvas which will become th image.
var context = canvas.getContext("2d");
canvas.width = canvas.height = 100;

// Draw the circle in the background using the randomColor.
context.fillStyle = randomColor;
context.beginPath();
context.ellipse(
  canvas.width / 2,
  canvas.height / 2, // Center x and y.
  canvas.width / 2,
  canvas.height / 2, // Horizontal and vertical "radius".
  0, // Rotation, useless for perfect circle.
  0,
  Math.PI * 2 // from and to angle: Full circle in radians.
);
context.fill();

context.font = "700 " + canvas.height / 3 + "px Helvetica";
context.fillStyle = fontColor;
// Make the text's center overlap the image's center.
context.textAlign = "center";
context.textBaseline = "middle";
context.fillText(initials, canvas.width / 2, canvas.height / 2);

// Show the image to the world.
console.log(canvas.toDataURL());
const fs = require("fs");
const out = fs.createWriteStream(__dirname + "/test.png");
const stream = canvas.createPNGStream();
stream.pipe(out);
out.on("finish", () => console.log("The PNG file was created."));

function getColors() {
  var randomColor =
    "#" + (0x1000000 | (Math.random() * 0xffffff)).toString(16).substr(1, 6);

  var fontColor = contrast(randomColor);

  return { background: randomColor, font: fontColor };
}

function rgbToPerceivedLuminance({ r, g, b }) {
  // used YIQ color space
  // Y component [0-255]
  return (r * 299 + g * 587 + b * 114) / 1000;
}

function hexToRgb(hex) {
  if (!hex || hex === undefined || hex === "") {
    return undefined;
  }

  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);

  return result
    ? {
        r: parseInt(result[1], 16),
        g: parseInt(result[2], 16),
        b: parseInt(result[3], 16),
      }
    : undefined;
}

function contrast(colorHex, threshold = 128) {
  if (colorHex === undefined) {
    return "#000";
  }

  const rgb = hexToRgb(colorHex);

  if (rgb === undefined) {
    return "#000";
  }

  return rgbToPerceivedLuminance(rgb) >= threshold ? "#000" : "#fff";
}
String.prototype.interpolate = function(params) {
  const names = Object.keys(params);
  const vals = Object.values(params);
  return new Function(...names, `return \`${this}\`;`)(...vals);
}

const template = 'Example text: ${text}';
const result = template.interpolate({
  text: 'Foo Boo'
});
console.log(result);
// app.component.ts

import { Component, OnInit } from '@angular/core';
import {  FileUploader, FileSelectDirective } from 'ng2-file-upload/ng2-file-upload';

const UploadURL = 'http://localhost:3000/api/upload';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'Upload a File';

  public uploader: FileUploader = new FileUploader({url: URL, itemAlias: 'photo'});

  ngOnInit() {
    this.uploader.onAfterAddingFile = (file) => { file.withCredentials = false; };
    this.uploader.onCompleteItem = (item: any, response: any, status: any, headers: any) => {
         console.log('FileUpload:uploaded:', item, status, response);
         alert('File uploaded successfully');
     };
 }
}
// app.component.ts

import { Component, OnInit } from '@angular/core';
import {  FileUploader, FileSelectDirective } from 'ng2-file-upload/ng2-file-upload';

const UploadURL = 'http://localhost:3000/api/upload';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
  title = 'Upload a File';

  public uploader: FileUploader = new FileUploader({url: URL, itemAlias: 'photo'});

  ngOnInit() {
    this.uploader.onAfterAddingFile = (file) => { file.withCredentials = false; };
    this.uploader.onCompleteItem = (item: any, response: any, status: any, headers: any) => {
         console.log('FileUpload:uploaded:', item, status, response);
         alert('File uploaded successfully');
     };
 }
}
//* Root Handler
app.get("/", (req, res) =>
  res.sendFile(path.join(__dirname + "/public/index.html"))
);

app.get('api/v1', (req,res) => res.json())

// Set static folder
app.use(express.static(path.join(__dirname, 'public')));

app.use('/api/v1', require('./routes/api/v1'))

app.listen(port, () => {
  console.log(`Server at: http://localhost:${port}`);
});
`Pomoci zpětné uvozovky vytvoříte speciální řetězec, který lze psát na více 
 řádků a dají se do něj vkládat výrazy ${ 1+2 }, proměnné ${ x+y }, pole ${ seznam[0] },
 objekty ${ uzivatelske.jmeno } a dokonce ihned volané funkce ${ function() { return x+y; }() } 
 nebo metody ${ "sidon".toUpperCase() }.`
      {arr.map(({ what ever you want to get from map }) => (
        <div>
			code goes here to display through html elements
        </div>
      ))}
// Bubble sorting using most of the important features in TypeScript

//* index.ts
import { Sorter } from './Sorter';
import { NumbersCollection } from './NumbersCollecton';

// Passing object into helper function to prepare variable for sorter when data is an array
const numbersCollection = new NumbersCollection([10, 3, -5, 0])
// Passing in object now instead of raw data
const sorter = new Sorter(numbersCollection)

sorter.sort()

console.log(numbersCollection.data)



//* Sorter.ts
import { NumbersCollection } from './NumbersCollecton';


export class Sorter {
  constructor(public collection: NumbersCollection)  {}

  sort(): void {
    const { length } = this.collection

    for (let i = 0; i < length; i++) {
      for (let j = 0; j < length - i - 1; j++) {
        if (this.collection.compare(j, j + 1)) {
          this.collection.swap(j, j+1)
        }
        // Only going to work if collecton is a string
        // If collection is a string, do this instead
        // ~~~logic to compare and swap characters in a string
      }
    }
  }
}



//* NumbersCollection.ts

/* Class Structure: */

// File: NumbersCollection.ts
// Class: NumbersCollection {
// Constructor: constructor(permissions, vars: types) {}
// Function(s) function(): type {
  // function body
// } //close function
// } // Close Class




export class NumbersCollection {
  // Require an array of numbers to be passed in and instantiated
  constructor(public data: number[]) {}
  // Need to get length of array
  get length(): number {
    return this.data.length
  }
  // decide if we need to swap 2 elements in a pair (bubble sort)
  /* is -1 > 0 ? If so, swap them
    /       |
  /        |
  [-1] [0] [5] [10] */
  compare(leftIndex: number, rightIndex: number): boolean {
    return this.data[leftIndex] > this.data[rightIndex]
  }

  swap(leftIndex: number, rightIndex: number): void {
    const leftHand = this.data[leftIndex]
    this.data[leftIndex] = this.data[rightIndex]
    this.data[rightIndex] = leftHand

  }

}

// const collection = new NumbersCollection([1,2,3])
// // since 'get' was used, length doesn't need to be called as a function (ex: collection.length())
// collection.length
array.sort((x, y) => +new Date(x.createdAt) - +new Date(y.createdAt));
// BASH
mkdir src
mkdir build
touch src/index.ts
touch .gitignore
touch README.md
tsc -y
npm init -y
npm install nodemon concurrently @types/express --save-dev

// package.json
...
"scripts": {
  "start:build": "tsc -w",
  "start:run": "nodemon ./build/index.js",
  "start": "concurrently npm:start:*"
},
...

// tsconfig.json
...
"outDir": "./build",
"rootDir": "./src",
...

// .gitignore
node_modules
*.env

// README.md
### Start
```bash
npm run start
```

// src/index.ts
import express from 'express'
const port = 3000
const app = express()

console.log("Hello, World!!!")

logSomething("This is a string that I'm logging")

app.listen(port, () => {
  console.log(`Listening on port ${port}`)
})
let rand = Math.random()
rand < 0.5 ? gender = 0 : gender = 1
this.name = `${gender ? '👩‍💼' : '👨‍💼'} ${faker.name.firstName(gender)} ${faker.name.lastName(gender)}`
import { User } from './User'
import { Company } from './Company'

// Instructions to every other class on how they can be an argument to 'addMarker'
// Interface acts as a gatekeeper for props. Does the prop qualify? If so, it can be an argument to the function
interface Mappable {
  location: {
    lat: number;
    lng: number;
  }
}

export class CustomMap {
  private googleMap: google.maps.Map;
  
  constructor(divId: string) {
    this.googleMap = new google.maps.Map(document.getElementById(divId), {
      zoom: 1,
      center: {
        lat: 0,
        lng: 0
      }
    })
  }

  // TS will compare User and Company types and only allow mutual props to be referenced in this function
  addMarker(mappable: Mappable): void {
    // typing 'mappable.' will use intellisense to show props that can be mapped here
    new google.maps.Marker({
      map: this.googleMap,
      position: {
        lat: mappable.location.lat,
        lng: mappable.location.lng
      }
    })
  }

}


// Company and User will be included below for reference
// Company.ts

import faker from 'faker'

export class Company {
  companyName: string;
  catchPhrase: string;
  location: {
    lat: number;
    lng: number;
  }

  constructor() {
    this.companyName = faker.company.companyName()
    this.catchPhrase = faker.company.catchPhrase()
    this.location = {
      lat: parseFloat(faker.address.latitude()),
      lng: parseFloat(faker.address.longitude())
    }

  }
}



// User.ts
import faker from 'faker'

// 'export' will export specific variables - imports will be done in curly braces
// 'export default' should nearly never be used in TypeScript - importing default exports won't use curly braces

export class User {
  name: string;
  location: {
    lat: number;
    lng: number;
  }

  // Objects aren't defined when the class is created so you can not assign values to keys without instantiating the object first
  constructor() {
    this.name = faker.name.firstName()
    this.location = {
      lat: parseFloat(faker.address.longitude()),
      lng: parseFloat(faker.address.latitude())
    } 
  }
}


// Execution - index files:
// index.ts
import faker from 'faker'

// 'export' will export specific variables - imports will be done in curly braces
// 'export default' should nearly never be used in TypeScript - importing default exports won't use curly braces

export class User {
  name: string;
  location: {
    lat: number;
    lng: number;
  }

  // Objects aren't defined when the class is created so you can not assign values to keys without instantiating the object first
  constructor() {
    this.name = faker.name.firstName()
    this.location = {
      lat: parseFloat(faker.address.longitude()),
      lng: parseFloat(faker.address.latitude())
    } 
  }
}

// index.html
// the 'DOCTYPE' heading will cause Google Maps to fail, not sure why
<!-- <!DOCTYPE html> -->
<html>
  <head charset="utf-8">
    <title>Maps</title>
  </head>
  <body>
    <div id="map" style="height: 100%"></div>
    <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBNLrJhOMz6idD05pzfn5lhA-TAw-mAZCU"></script>
    <script src="./src/index.ts"></script>
  </body>
</html>
interface IIsObject {
  (item: any): boolean;
}

interface IObject {
  [key: string]: any;
}

interface IDeepMerge {
  (target: IObject, ...sources: Array<IObject>): IObject;
}

/**
 * @description Method to check if an item is an object. Date and Function are considered
 * an object, so if you need to exclude those, please update the method accordingly.
 * @param item - The item that needs to be checked
 * @return {Boolean} Whether or not @item is an object
 */
export const isObject: IIsObject = (item: any): boolean => {
  return (item === Object(item) && !Array.isArray(item));
};

/**
 * @description Method to perform a deep merge of objects
 * @param {Object} target - The targeted object that needs to be merged with the supplied @sources
 * @param {Array<Object>} sources - The source(s) that will be used to update the @target object
 * @return {Object} The final merged object
 */
export const deepMerge: IDeepMerge = (target: IObject, ...sources: Array<IObject>): IObject => {
  // return the target if no sources passed
  if (!sources.length) {
    return target;
  }

  const result: IObject = target;

  if (isObject(result)) {
    const len: number = sources.length;

    for (let i = 0; i < len; i += 1) {
      const elm: any = sources[i];

      if (isObject(elm)) {
        for (const key in elm) {
          if (elm.hasOwnProperty(key)) {
            if (isObject(elm[key])) {
              if (!result[key] || !isObject(result[key])) {
                result[key] = {};
              }
              deepMerge(result[key], elm[key]);
            } else {
              if (Array.isArray(result[key]) && Array.isArray(elm[key])) {
                // concatenate the two arrays and remove any duplicate primitive values
                result[key] = Array.from(new Set(result[key].concat(elm[key])));
              } else {
                result[key] = elm[key];
              }
            }
          }
        }
      }
    }
  }

  return result;
};
import { IOrdersRepository, OrderRepository } from './../repositories/OrderRepository';
import * as Knex  from 'knex';
import { IProductsRepository, ProductsRepository } from './../repositories/ProductsRepository';
import { IUserRepository, UserRepository } from './../repositories/UserRepository';

export interface IUnitOfWork {
    commit(): void;
    rollback(): void
}

// Requires a transaction scope injected on a per-request basis.
export class UnitOfWork implements IUnitOfWork {
    private context: Knex.Transaction;

    public readonly usersRepository: IUserRepository;
    public readonly ordersRepository: IOrdersRepository;
    public readonly productsRepository: IProductsRepository;

    public constructor(transactionContext: Knex.Transaction) {
        this.context = transactionContext;

        this.usersRepository = new UserRepository(transactionContext);
        this.ordersRepository = new OrderRepository(transactionContext);
        this.productsRepository = new ProductsRepository(transactionContext);
    }

    public commit(): void {
        this.context.commit();
    }

    public rollback(): void {
        this.context.rollback();
    }
}
  it.only('Only a Care Team member can view a "Patient Profile".', () => {
    const proUser = users.proUser();
    const confirmedPatient = users.patient();
    userBasePage.createProfessional(proUser, process.env.COUNTRYAPI);
    const patient = userBasePage.createPatient(
      process.env.LANGUAGE,
      false,
      confirmedPatient,
      process.env.COUNTRYAPI,
    );
    const practiseData = fixtureHelper.getFixture('practices').sharedPractice();
    const practice = userBasePage.createSharedPractice(proUser, practiseData);
    userBasePage.addPracticeToPatient(patient, practice.practiceId);
    const proUserTemplateList = userBasePage.createProUsers(
      4,
      proUser,
      practice.id,
    );

    CountryOfResidencePage.open().submitForm(
      process.env.COUNTRY,
      process.env.LANGUAGE,
    );
    IndexPage.login(proUser.email, proUser.password)
      .goToPatientsDashboard()
      .closeFirstUseModal();
    PatientDashboardPage.openUserProfile(patient.firstName);
    PatientProfilePage.closeFirstUseModal().clickOnProfileNavButton();
    NavigationBar.clickMainHeaderHamburgerButton();
    MenuBarFrame.clickMenuSignOutLink();
    IndexPage.login(
      proUserTemplateList[0].email,
      proUserTemplateList[0].password,
      proUserTemplateList[0],
      true,
    )
      .goToPatientsDashboard()
      .closeFirstUseModal();
    PatientDashboardPage.openUserProfile(patient.firstName);
    PatientProfilePage.closeFirstUseModal().clickOnProfileNavButton();
    NavigationBar.clickMainHeaderHamburgerButton();
    MenuBarFrame.clickMenuSignOutLink();
    IndexPage.login(
      proUserTemplateList[1].email,
      proUserTemplateList[1].password,
      proUserTemplateList[1],
      true,
    )
      .goToPatientsDashboard()
      .closeFirstUseModal();
    PatientDashboardPage.openUserProfile(patient.firstName);
    PatientProfilePage.closeFirstUseModal().clickOnProfileNavButton();
    NavigationBar.clickMainHeaderHamburgerButton();
    MenuBarFrame.clickMenuSignOutLink();
    IndexPage.login(
      proUserTemplateList[2].email,
      proUserTemplateList[2].password,
      proUserTemplateList[2],
      true,
    )
      .goToPatientsDashboard()
      .closeFirstUseModal();
    PatientDashboardPage.openUserProfile(patient.firstName);
    PatientProfilePage.closeFirstUseModal().clickOnProfileNavButton();
    NavigationBar.clickMainHeaderHamburgerButton();
    MenuBarFrame.clickMenuSignOutLink();
    IndexPage.login(
      proUserTemplateList[3].email,
      proUserTemplateList[3].password,
      proUserTemplateList[3],
      true,
    )
      .goToPatientsDashboard()
      .closeFirstUseModal();
    PatientDashboardPage.openUserProfile(patient.firstName);
    PatientProfilePage.closeFirstUseModal().clickOnProfileNavButton();
  });
const a = [
    {
        k: 1, me: false, prim: false
    }, {
        k: 2, me: false, prim: false
    }, {
        k: 3, me: false, prim: false
    }, {
        k: 4, me: false, prim: false
    }, {
        k: 5, me: true, prim: true
    }, {
        k: 6, me: false, prim: false
    }
]

a
    .sort((x, y) => (x.prim === y.prim) ? 0 : x.prim ? -1 : 1)
    .sort((x, y) => (x.me === y.me) ? 0 : x.me ? -1 : 1)

console.log(a)
function Test(): void {
 console.log('test')
 }
star

Wed May 22 2024 09:24:46 GMT+0000 (Coordinated Universal Time)

#typescript
star

Fri May 10 2024 11:59:31 GMT+0000 (Coordinated Universal Time) https://www.codewhy.net/typescript/537.html

#typescript
star

Sat Apr 20 2024 17:03:31 GMT+0000 (Coordinated Universal Time)

#typescript
star

Mon Apr 15 2024 05:10:24 GMT+0000 (Coordinated Universal Time)

#typescript
star

Fri Feb 09 2024 12:58:37 GMT+0000 (Coordinated Universal Time)

#typescript
star

Fri Feb 09 2024 09:49:14 GMT+0000 (Coordinated Universal Time)

#typescript
star

Fri Feb 09 2024 09:30:02 GMT+0000 (Coordinated Universal Time)

#typescript
star

Fri Feb 09 2024 09:24:36 GMT+0000 (Coordinated Universal Time)

#typescript
star

Fri Feb 09 2024 09:21:29 GMT+0000 (Coordinated Universal Time)

#typescript
star

Fri Feb 09 2024 08:41:37 GMT+0000 (Coordinated Universal Time)

#typescript
star

Fri Feb 09 2024 08:26:18 GMT+0000 (Coordinated Universal Time)

#typescript
star

Fri Dec 29 2023 20:02:37 GMT+0000 (Coordinated Universal Time) https://api.getmerlin.in/docs/gemini-models

#typescript
star

Fri Dec 29 2023 20:02:28 GMT+0000 (Coordinated Universal Time) https://api.getmerlin.in/docs/gemini-models

#typescript
star

Sun Dec 10 2023 12:34:37 GMT+0000 (Coordinated Universal Time) https://ayedot.com/6231/MiniBlog/Day-1--Christmas-Cookies--Typehero-Advent-of-TypeScript-Challenge-

#typescript
star

Thu Nov 23 2023 23:12:42 GMT+0000 (Coordinated Universal Time)

#typescript #react.js
star

Tue Oct 17 2023 10:33:44 GMT+0000 (Coordinated Universal Time)

#typescript #react #polymorphic
star

Wed Sep 20 2023 09:17:12 GMT+0000 (Coordinated Universal Time)

#typescript
star

Wed Sep 20 2023 09:16:20 GMT+0000 (Coordinated Universal Time)

#typescript