Skip to content

Commit

Permalink
Merge pull request #428 from shawakash/client_set
Browse files Browse the repository at this point in the history
feat: adds local update button
  • Loading branch information
shawakash authored Apr 20, 2024
2 parents dcecacb + f6f2a20 commit 4c9ae9d
Show file tree
Hide file tree
Showing 25 changed files with 720 additions and 63 deletions.
71 changes: 71 additions & 0 deletions apps/web/app/profile/settings/components/locale-btn.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"use client";
import { CommandMenu } from '@/components/combo-box';
import { Button } from '@/components/ui/button';
import { langs } from '@/lib/contants';
import { updateLocale } from '@/lib/helper';
import { getLocaleName } from '@/lib/utils';
import { Locales } from '@paybox/common';
import { clientJwtAtom, localeAtom } from '@paybox/recoil';
import { ChevronRight } from 'lucide-react';
import React, { useEffect } from 'react'
import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil';
import { toast } from 'sonner';

function LocaleButton({
locale
}: {
locale: Locales
}) {
const [open, setOpen] = React.useState(false);
let [changedLocale, setChangedLocale] = React.useState<string>();
const [localeState, setLocale] = useRecoilState(localeAtom);
const jwt = useRecoilValue(clientJwtAtom);

useEffect(() => {
setLocale(locale);
}, [locale]);

useEffect(() => {
if (changedLocale) {
if(jwt) {
toast.promise(updateLocale(jwt, changedLocale as Locales), {
loading: 'Updating locale...',
success: () => {
setLocale(changedLocale as Locales);
return 'Locale updated successfully';
},
error: ({msg}) => {
return msg || 'Failed to update locale';
}
});
} else {
toast.error('Auth Token not found. Please login again.');

}
}
}, [changedLocale]);

return (
<>
<div className='w-full' onClick={() => {
setOpen(true);
}}>
<Button variant={"secondary"} className="w-full justify-between">
<span className="">Display Language</span>
<span className="text-muted-foreground flex gap-x-1 items-center">{getLocaleName(locale)} <ChevronRight className="w-4 h-4" /></span>
</Button>
</div>
<CommandMenu
onSelect={setChangedLocale}
options={langs}
setOpen={setOpen}
strokeKey='l'
open={open}
heading='Languages'
selected={localeState}
/>
</>
)
}

export default LocaleButton
38 changes: 36 additions & 2 deletions apps/web/app/profile/settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,34 @@ import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Switch } from "@/components/ui/switch"

import { Terminal } from "lucide-react";
import { ChevronRight, Languages, Terminal } from "lucide-react";
import TestModeSwitch from "./components/test-mode";
import LocaleButton from "./components/locale-btn";
import { BACKEND_URL, Locales, responseStatus } from "@paybox/common";

//todo: get the local from db if not set, set it to en
const getLocale = async (jwt: string) => {
try {
const { status, locale, msg }: { status: responseStatus, locale: Locales, msg?: string }
= await fetch(`${BACKEND_URL}/locale/locale`, {
method: "GET",
headers: {
"Content-type": "application/json",
authorization: `Bearer ${jwt}`,
},
cache: "no-cache"
}).then(res => res.json());
console.log(locale);
if (status === responseStatus.Error) {
console.log(msg)
return Locales.en;
}
return locale;
} catch (error) {
console.log(error);
return Locales.en;
}
}


export default async function Home({
Expand All @@ -37,7 +62,7 @@ export default async function Home({
if (!jwt) {
redirect('/signin');
}

const locale = await getLocale(jwt) || Locales.en;

const layout = cookies().get("react-resizable-panels:layout");
const defaultLayout = layout ? JSON.parse(layout.value) : undefined;
Expand Down Expand Up @@ -90,6 +115,15 @@ export default async function Home({
</DialogFooter>
</DialogContent>
</Dialog>
<div className="flex w-2/3 items-center space-x-2">
<Button className="gap-x-2 px-2 cursor-none">
<Languages className="w-5 h-5" />
<span className="font-bold">
Locale
</span>
</Button>
<LocaleButton locale={locale} />
</div>
</div>

</main>
Expand Down
1 change: 0 additions & 1 deletion apps/web/components/buy-combo.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ export function TokenCommandMenu({
<Button
className="w-full h-fit gap-x-2 flex justify-start p-0 cursor-pointer border-none bg-transparent" variant={"secondary"}
onClick={() => {
console.log("here")
setOpen(false);
onSelect(token.value);
}}
Expand Down
82 changes: 82 additions & 0 deletions apps/web/components/combo-box.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"use client";
import {
Command,
CommandDialog,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
CommandSeparator,
CommandShortcut,
} from "@/components/ui/command"
import React from "react"
import { Button } from "./ui/button"
import { CheckCheck } from "lucide-react";


interface Option {
name: string,
value: string,
}

export function CommandMenu({
open,
setOpen,
onSelect,
options,
strokeKey,
heading,
selected
}: {
open: boolean,
setOpen: React.Dispatch<React.SetStateAction<boolean>>
onSelect: (value: string) => void,
options: Option[],
strokeKey: string,
heading: string,
selected: string
}) {

React.useEffect(() => {
const down = (e: KeyboardEvent) => {
if (e.key === strokeKey && (e.metaKey || e.ctrlKey)) {
e.preventDefault()
setOpen((open) => !open)
}
}
document.addEventListener("keydown", down)
return () => document.removeEventListener("keydown", down)
}, [])

return (
<CommandDialog open={open} onOpenChange={setOpen}>
<CommandInput placeholder="Type to make life simpler..." />
<CommandList>
<CommandEmpty>No results found.</CommandEmpty>
<CommandGroup heading={heading}>
{options.map((option) => (
<CommandItem
className=""
key={option.value}
>
<Button
className="w-full h-fit gap-x-2 flex justify-between p-0 cursor-pointer border-none bg-transparent" variant={"secondary"}
onClick={() => {
setOpen(false);
onSelect(option.value);
}}
>
<div className="">{option.name}</div>
{selected === option.value && <CheckCheck />}
</Button>
</CommandItem>
))}
</CommandGroup>
<CommandSeparator />
</CommandList>


</CommandDialog>
)
}
13 changes: 13 additions & 0 deletions apps/web/lib/contants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export const langs = [
{ name: 'English', value: 'en' },
{ name: 'Español', value: 'es' },
{ name: 'Français', value: 'fr' },
{ name: 'Deutsch', value: 'de' },
{ name: 'Italiano', value: 'it' },
{ name: 'Português', value: 'pt' },
{ name: 'Русский', value: 'ru' },
{ name: '中文', value: 'zh' },
{ name: '日本語', value: 'ja' },
{ name: '한국어', value: 'ko' },
{ name: 'हिन्दी', value: 'hi' },
]
46 changes: 38 additions & 8 deletions apps/web/lib/helper.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import crypto from 'crypto';
import { PRIVATE_KEY_ENCRYPTION_KEY } from './config';
import { AccountType, BACKEND_URL, FriendPubKeys, FriendshipStatusEnum, FriendshipType, NotifType, WS_BACKEND_URL, responseStatus } from '@paybox/common';
import { AccountType, BACKEND_URL, FriendPubKeys, FriendshipStatusEnum, FriendshipType, Locales, NotifType, WS_BACKEND_URL, responseStatus } from '@paybox/common';

export function toBase64(file: File) {
return new Promise((resolve, reject) => {
Expand Down Expand Up @@ -238,11 +238,11 @@ export const updateNotif = async (
* @returns
*/
export const markViewed = async (
jwt: string,
jwt: string,
notifIds: string[]
): Promise<{status: responseStatus, msg?: string}> => {
): Promise<{ status: responseStatus, msg?: string }> => {
try {
const {status}: {status: responseStatus} = await fetch(`${BACKEND_URL}/notif/viewed`, {
const { status }: { status: responseStatus } = await fetch(`${BACKEND_URL}/notif/viewed`, {
method: "PUT",
headers: {
"Content-type": "application/json",
Expand All @@ -251,13 +251,43 @@ export const markViewed = async (
body: JSON.stringify({ ids: notifIds }),
cache: "no-cache"
}).then(res => res.json());
if(status === responseStatus.Error) {
if (status === responseStatus.Error) {
console.log("error marking notifications as viewed");
return Promise.reject({msg: "error marking notifications as viewed", status: responseStatus.Error});
return Promise.reject({ msg: "error marking notifications as viewed", status: responseStatus.Error });
}
return Promise.resolve({status: responseStatus.Ok});
return Promise.resolve({ status: responseStatus.Ok });
} catch (error) {
console.log(error);
return Promise.reject({ msg: "error marking notifications as viewed", status: responseStatus.Error });
}
}

/**
* Fetch to update locale
* @param jwt
* @param locale
* @returns
*/
export const updateLocale = async (
jwt: string,
locale: Locales
): Promise<void> => {
try {
const { status, msg }: { status: responseStatus, msg?: string } =
await fetch(`${BACKEND_URL}/locale?locale=${locale}`, {
method: "get",
headers: {
"Content-type": "application/json",
authorization: `Bearer ${jwt}`,
},
cache: "force-cache"
}).then(res => res.json());
if(status == responseStatus.Error) {
return Promise.reject({ msg: "error updating locale", status: responseStatus.Error });
}
return Promise.resolve();
} catch (error) {
console.log(error);
return Promise.reject({msg: "error marking notifications as viewed", status: responseStatus.Error});
return Promise.reject({ msg: "error updating locale", status: responseStatus.Error });
}
}
6 changes: 6 additions & 0 deletions apps/web/lib/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import { Locales } from "@paybox/common";
import { type ClassValue, clsx } from "clsx";
import { twMerge } from "tailwind-merge";
import { langs } from "./contants";

export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}

export const getLocaleName = (locale: Locales): string => {
return langs.find(({value}) => value == locale)?.name || "";
}
1 change: 1 addition & 0 deletions backend/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"@moonpay/moonpay-node": "^0.2.5",
"@paybox/backend-common": "*",
"@paybox/common": "^0.1.5",
"@paybox/zeus": "^0.1.2",
"@paybox/openapi": "^0.1.2",
"@solana/spl-token": "^0.3.11",
"@solana/wallet-adapter-wallets": "^0.19.26",
Expand Down
40 changes: 40 additions & 0 deletions backend/api/src/db/locale.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Chain } from "@paybox/zeus";
import { HASURA_URL, JWT } from "../config";
import { HASURA_ADMIN_SERCRET, Locales, dbResStatus } from "@paybox/common";

const chain = Chain(HASURA_URL, {
headers: {
Authorization: `Bearer ${JWT}`,
"x-hasura-admin-secret": HASURA_ADMIN_SERCRET,
},
});

/**
* @param clientId
*/
export const getLocale = async (
clientId: string
): Promise<{
status: dbResStatus,
locale?: Locales
}> => {
const response = await chain("query")({
client_settings: [{
limit: 1,
where: {
clientId: {_eq: clientId}
},
}, {
locale: true
}]
}, {operationName: "getLocale"});
if(response.client_settings[0].locale) {
return {
locale: response.client_settings[0].locale as Locales,
status: dbResStatus.Ok
}
}
return {
status: dbResStatus.Error
}
}
2 changes: 2 additions & 0 deletions backend/api/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import { notifRouter } from "./routes/notif";
import { MoonPay } from "@moonpay/moonpay-node";
import { buyRouter } from "./routes/buy";
import { hooksRouter } from "./routes/webhooks";
import { localeRouter } from "./routes/locale";


export * from "./Redis";
Expand Down Expand Up @@ -161,6 +162,7 @@ app.use('/notif', extractClientId, checkValidation, notifRouter);
app.use('/notif_sub', extractClientId, notifSubRouter);
app.use('/buy', extractClientId, checkValidation, buyRouter);
app.use('/hooks', hooksRouter);
app.use('/locale', localeRouter);

app.get("/metrics", async (_req, res) => {
res.set("Content-Type", Prometheus.register.contentType);
Expand Down
Loading

0 comments on commit 4c9ae9d

Please sign in to comment.