Added deeplinks, added qr code login, added settings, other stuff

This commit is contained in:
Alois 2026-04-10 19:44:08 +02:00
commit 8ff8bd9528
32 changed files with 917 additions and 78 deletions

View file

@ -1,5 +1,5 @@
import { Button } from "@tensamin/ui/cmp/button";
import { ArrowLeft, House, Phone, User } from "lucide-react";
import { ArrowLeft, House, Phone, Settings, User } from "lucide-react";
import { useLocation, useNavigate, useSearch } from "@tanstack/react-router";
import { useCall } from "@tensamin/call/context";
import Wrapper from "@tensamin/user/wrapper";
@ -22,6 +22,7 @@ export default function Navbar({ forMobile }: { forMobile: boolean }) {
const { contacts } = useTTP();
const { pathname } = useLocation();
const { id } = useSearch({ strict: false });
const currentCalls = id ? contacts?.[id]?.calls || [] : [];
@ -43,13 +44,23 @@ export default function Navbar({ forMobile }: { forMobile: boolean }) {
<ArrowLeft className="size-4.5" />
</SidebarTrigger>
) : (
<Button
onClick={() => navigate({ to: "/" })}
className="w-9 h-9 aspect-square rounded-lg"
variant="outline"
>
<House className="size-4.5" />
</Button>
<>
<Button
onClick={() => navigate({ to: "/" })}
className="w-9 h-9 aspect-square rounded-lg"
variant="outline"
>
<House className="size-4.5" />
</Button>
<Button
// @ts-expect-error TanStack router doesn't properly detect the settings route
onClick={() => navigate({ to: "/settings" })}
className="w-9 h-9 aspect-square rounded-lg"
variant="outline"
>
<Settings className="size-4.5" />
</Button>
</>
)}
{pathname === "/chat" && (
<Wrapper
@ -126,22 +137,36 @@ export function MobileNavbar() {
return (
<div className="z-51 w-full pb-[env(safe-area-inset-bottom)] bg-card border-t">
<div className="z-51 w-full h-14 flex justify-center items-center gap-8">
<div className="z-51 w-full h-15 grid grid-cols-3 items-center place-items-center px-5">
<SidebarTrigger
className="text-foreground w-12! h-12! aspect-square rounded-xl"
className="text-foreground w-12! h-12! aspect-square rounded-xl flex flex-col gap-1"
variant="link"
>
<User className="size-5.5" />
<User className="size-4.5" />
<p className="text-xs">Chats</p>
</SidebarTrigger>
<Button
onClick={() => {
navigate({ to: "/" });
setOpenMobile(false);
}}
className="text-foreground w-12 h-12 aspect-square rounded-xl"
className="text-foreground w-12 h-12 aspect-square rounded-xl flex flex-col gap-1"
variant="link"
>
<House className="size-5.5" />
<House className="size-4.5" />
<p className="text-xs">Home</p>
</Button>
<Button
onClick={() => {
// @ts-expect-error TanStack router doesn't properly detect the settings route
navigate({ to: "/settings" });
setOpenMobile(false);
}}
className="text-foreground w-12 h-12 aspect-square rounded-xl flex flex-col gap-1"
variant="link"
>
<Settings className="size-4.5" />
<p className="text-xs">Settings</p>
</Button>
</div>
</div>

View file

@ -6,6 +6,8 @@ import { log, toast } from "@tensamin/shared/log";
import { File } from "lucide-react";
import * as React from "react";
import { z } from "zod";
import { isTauri } from "@tauri-apps/api/core";
import QrCodeScanner from "@tensamin/tauri/qrCodeScanner";
const fetchedUser = z.object({
id: z.uuidv4(),
@ -145,15 +147,46 @@ export default function Form() {
[save],
);
const isTauriEnv = isTauri();
return (
<div className="flex md:flex-row flex-col gap-15">
<div
onClick={() => uploadRef.current?.click()}
className="flex flex-col gap-3 cursor-pointer w-55 aspect-square bg-input/13 hover:bg-input/30 transition-all duration-300 ease-in-out border-3 items-center justify-center rounded-lg"
>
<File className="text-foreground" size={27} />
<p className="text-md">Select .tu file</p>
</div>
{isTauriEnv ? (
<>
<QrCodeScanner
onData={(data) => {
if (!data.startsWith("tensamin://tu::")) {
toast("error", "Invalid QR code");
return;
} else {
const decoded = data.replace("tensamin://tu::", "");
try {
const { userId, privateKey } = parseTuFileContent(decoded);
save("session_id", Date.now());
save("user_id", userId);
save("private_key", privateKey);
location.href = "/";
} catch (error) {
log(0, "login", "red", error);
toast("error", "Failed to parse QR code data");
}
}
}}
/>
<Button onClick={() => uploadRef.current?.click()}>
Select .tu file
</Button>
</>
) : (
<div
onClick={() => uploadRef.current?.click()}
className="flex flex-col gap-3 cursor-pointer w-55 aspect-square bg-input/13 hover:bg-input/30 transition-all duration-300 ease-in-out border-3 items-center justify-center rounded-lg"
>
<File className="text-foreground" size={27} />
<p className="text-md">Select .tu file</p>
</div>
)}
<input
accept=".tu"
onChange={handleFileInputChange}

View file

@ -10,9 +10,9 @@ import {
import { isTauri } from "@tauri-apps/api/core";
import { useIsMobile } from "@tensamin/ui/utils";
import { MobileNavbar } from "./navbar";
import { useLocation } from "@tanstack/react-router";
import SidebarBox from "@tensamin/call/sidebarBox";
import { useShowMobileNavbar } from "@/routes/app/layout";
/**
* Renders the conversation sidebar with account summary and conversation list.
@ -20,7 +20,7 @@ import SidebarBox from "@tensamin/call/sidebarBox";
*/
export default function Sidebar() {
const isMobile = useIsMobile();
const location = useLocation();
const showMobileNavbar = useShowMobileNavbar();
return (
<SidebarRoot>
@ -42,7 +42,7 @@ export default function Sidebar() {
</div>
</div>
</SidebarContent>
{isMobile && location.pathname === "/chat" && (
{isMobile && !showMobileNavbar && (
<SidebarFooter className="p-0!">
<MobileNavbar />
</SidebarFooter>