(feat): improved conversation adding flow
(feat): visual tweaks for user modal (feat): now using full width for profile settings page on mobile (fix): profile not saving with empty avatar (chore): bump version due to prod release not getting created (chore): update licenses
This commit is contained in:
parent
4380d664be
commit
ba59a49f98
14 changed files with 203 additions and 44 deletions
|
|
@ -31,12 +31,12 @@ export function Basic({
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger
|
<TooltipTrigger
|
||||||
render={
|
render={
|
||||||
<div className="absolute -bottom-0.75 -right-0.75 z-10 flex h-4 w-4 items-center justify-center rounded-full bg-card">
|
<div className="absolute -bottom-0.5 -right-0.5 z-10 flex h-3.5 w-3.5 items-center justify-center rounded-full bg-card">
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: getStatusColor(user.online_status),
|
backgroundColor: getStatusColor(user.online_status),
|
||||||
}}
|
}}
|
||||||
className="h-2.5 w-2.5 rounded-full"
|
className="h-2.25 w-2.25 rounded-full"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
@ -52,7 +52,7 @@ export function Basic({
|
||||||
<div className="flex flex-col gap-1 w-full items-start justify-center text-[15px]">
|
<div className="flex flex-col gap-1 w-full items-start justify-center text-[15px]">
|
||||||
<p>{user.display}</p>
|
<p>{user.display}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="pr-2">{extra}</div>
|
<div className="pr-1">{extra}</div>
|
||||||
</CardHeader>
|
</CardHeader>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ export default function Navbar({ forMobile }: { forMobile: boolean }) {
|
||||||
const currentCalls = calls.filter((call) =>
|
const currentCalls = calls.filter((call) =>
|
||||||
call.call_members.some((member) => member === id),
|
call.call_members.some((member) => member === id),
|
||||||
);
|
);
|
||||||
//const currentCalls = ["leck", "schleck", "und", "eck"];
|
|
||||||
|
|
||||||
const [selectOpen, setSelectOpen] = useState(false);
|
const [selectOpen, setSelectOpen] = useState(false);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -220,7 +220,7 @@ export default function Sidebar() {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
aria-label="Open profile menu"
|
aria-label="Open profile menu"
|
||||||
className="inline-flex h-8 w-8 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground"
|
className="cursor-pointer inline-flex h-8 w-8 items-center justify-center rounded-full text-muted-foreground transition-colors hover:bg-accent hover:text-accent-foreground"
|
||||||
>
|
>
|
||||||
<Ellipsis />
|
<Ellipsis />
|
||||||
</button>
|
</button>
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,16 @@ export default function List() {
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
|
<p
|
||||||
|
className="text-center text-sm px-2 text-muted-foreground transition-all duration-200 ease-in-out"
|
||||||
|
hidden={contacts.length !== 0 || category !== "conversations"}
|
||||||
|
style={{
|
||||||
|
opacity:
|
||||||
|
contacts.length === 0 && category === "conversations" ? 1 : 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Get started by adding a conversation
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,12 @@ import {
|
||||||
useIsMobile,
|
useIsMobile,
|
||||||
} from "@tensamin/ui";
|
} from "@tensamin/ui";
|
||||||
import z from "zod";
|
import z from "zod";
|
||||||
import { toast } from "@tensamin/shared/log";
|
|
||||||
import { useTTP } from "@tensamin/ttp";
|
import { useTTP } from "@tensamin/ttp";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import { Loader2 } from "lucide-react";
|
import { Loader2 } from "lucide-react";
|
||||||
import { isTauri } from "@tauri-apps/api/core";
|
import { isTauri } from "@tauri-apps/api/core";
|
||||||
import { useStorage } from "@tensamin/storage/context";
|
import { useStorage } from "@tensamin/storage/context";
|
||||||
|
import { useSession } from "@tensamin/storage/session";
|
||||||
|
|
||||||
// The page
|
// The page
|
||||||
export default function Page() {
|
export default function Page() {
|
||||||
|
|
@ -43,11 +43,16 @@ export default function Page() {
|
||||||
// Add Conversation Button Component
|
// Add Conversation Button Component
|
||||||
function AddConversationButton() {
|
function AddConversationButton() {
|
||||||
const { send } = useTTP();
|
const { send } = useTTP();
|
||||||
|
const { contacts, insertContact } = useSession();
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
|
const [open, setOpen] = useState(false);
|
||||||
|
const [error, setError] = useState<string | null>(null);
|
||||||
|
|
||||||
function submit(username: string | null) {
|
async function submit(username: string | null) {
|
||||||
if (loading) return;
|
if (loading) return;
|
||||||
|
setError(null);
|
||||||
|
|
||||||
|
// username check
|
||||||
const schema = z
|
const schema = z
|
||||||
.string()
|
.string()
|
||||||
.min(1, "Username is too short")
|
.min(1, "Username is too short")
|
||||||
|
|
@ -56,26 +61,50 @@ function AddConversationButton() {
|
||||||
const result = schema.safeParse(username?.toLowerCase().trim());
|
const result = schema.safeParse(username?.toLowerCase().trim());
|
||||||
|
|
||||||
if (!result.success) {
|
if (!result.success) {
|
||||||
toast("error", result.error.issues[0].message);
|
setError(result.error.issues[0].message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// user existence check
|
||||||
|
const user = await send("get_user_data", {
|
||||||
|
username: result.data,
|
||||||
|
})
|
||||||
|
.then((data) => {
|
||||||
|
if (data.data.user_id === 0) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
setError("User not found");
|
||||||
|
return;
|
||||||
|
});
|
||||||
|
if (!user) return;
|
||||||
|
|
||||||
|
// alrady added check
|
||||||
|
if (contacts.some((contact) => contact.user_id === user.data.user_id)) {
|
||||||
|
setError("Conversation already exists");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add the conv
|
||||||
const timeout = setTimeout(() => setLoading(true), 500);
|
const timeout = setTimeout(() => setLoading(true), 500);
|
||||||
|
|
||||||
send("add_conversation", {
|
send("add_conversation", {
|
||||||
chat_partner_name: result.data,
|
chat_partner_name: result.data,
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
toast("success", "Conversation added");
|
insertContact(user.data.user_id);
|
||||||
|
setOpen(false);
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
if (String(error).includes("error_not_found")) {
|
if (String(error).includes("error_not_found")) {
|
||||||
toast("error", "User not found");
|
setError("User not found");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
toast("error", "Failed to add conversation, check console for details");
|
setError(String(error));
|
||||||
console.error("Failed to add conversation", error);
|
|
||||||
})
|
})
|
||||||
.finally(() => {
|
.finally(() => {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
|
|
@ -84,7 +113,15 @@ function AddConversationButton() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Dialog>
|
<Dialog
|
||||||
|
open={open}
|
||||||
|
onOpenChange={(value) => {
|
||||||
|
if (value) {
|
||||||
|
setError(null);
|
||||||
|
}
|
||||||
|
setOpen(value);
|
||||||
|
}}
|
||||||
|
>
|
||||||
<DialogTrigger render={<Button>Add Conversation</Button>} />
|
<DialogTrigger render={<Button>Add Conversation</Button>} />
|
||||||
<DialogContent>
|
<DialogContent>
|
||||||
<DialogHeader>
|
<DialogHeader>
|
||||||
|
|
@ -110,7 +147,10 @@ function AddConversationButton() {
|
||||||
name="username"
|
name="username"
|
||||||
placeholder="Enter username..."
|
placeholder="Enter username..."
|
||||||
/>
|
/>
|
||||||
<div className="flex w-full justify-end gap-1">
|
<div className="flex w-full justify-end items-center gap-1">
|
||||||
|
{error && (
|
||||||
|
<p className="text-sm text-destructive w-full">{error}</p>
|
||||||
|
)}
|
||||||
<DialogClose render={<Button variant="outline">Cancel</Button>} />
|
<DialogClose render={<Button variant="outline">Cancel</Button>} />
|
||||||
<Button disabled={loading} type="submit">
|
<Button disabled={loading} type="submit">
|
||||||
{loading && <Loader2 className="animate-spin" />} Continue
|
{loading && <Loader2 className="animate-spin" />} Continue
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,9 @@ import {
|
||||||
AvatarFallback,
|
AvatarFallback,
|
||||||
AvatarImage,
|
AvatarImage,
|
||||||
Button,
|
Button,
|
||||||
|
cn,
|
||||||
Input,
|
Input,
|
||||||
|
useIsMobile,
|
||||||
} from "@tensamin/ui";
|
} from "@tensamin/ui";
|
||||||
import { useUser, type User } from "@tensamin/user/context";
|
import { useUser, type User } from "@tensamin/user/context";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
@ -83,6 +85,8 @@ export default function Page() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const isMobile = useIsMobile();
|
||||||
|
|
||||||
return currentUser ? (
|
return currentUser ? (
|
||||||
<>
|
<>
|
||||||
<input
|
<input
|
||||||
|
|
@ -93,7 +97,7 @@ export default function Page() {
|
||||||
}
|
}
|
||||||
type="file"
|
type="file"
|
||||||
/>
|
/>
|
||||||
<div className="flex flex-col gap-5 w-80">
|
<div className={cn("flex flex-col gap-5", isMobile ? "w-full" : "w-80")}>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<Avatar className="size-14">
|
<Avatar className="size-14">
|
||||||
<AvatarImage src={effectiveAvatar} />
|
<AvatarImage src={effectiveAvatar} />
|
||||||
|
|
@ -121,7 +125,7 @@ export default function Page() {
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-muted-foreground">
|
<p className="text-sm text-muted-foreground">
|
||||||
GIFs are supported in decentralised mode or with Tensamin Premium
|
GIFs are supported in decentralised mode or with Tensamin Premium.
|
||||||
<br />
|
<br />
|
||||||
Maximum file size is 16mb.
|
Maximum file size is 16mb.
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -162,13 +166,16 @@ export default function Page() {
|
||||||
/>
|
/>
|
||||||
<Button
|
<Button
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
|
const { avatar, ...draftUsersWithoutAvatar } = draftUser;
|
||||||
const payload = {
|
const payload = {
|
||||||
...draftUser,
|
...draftUsersWithoutAvatar,
|
||||||
avatar:
|
...(typeof avatar === "string"
|
||||||
typeof draftUser.avatar === "string" &&
|
? {
|
||||||
draftUser.avatar.startsWith("data:")
|
avatar: avatar.startsWith("data:")
|
||||||
? (draftUser.avatar.split(",", 2)[1] ?? "")
|
? (avatar.split(",", 2)[1] ?? "")
|
||||||
: draftUser.avatar,
|
: avatar,
|
||||||
|
}
|
||||||
|
: {}),
|
||||||
};
|
};
|
||||||
|
|
||||||
const validation = ttp.change_user_data.request.safeParse(payload);
|
const validation = ttp.change_user_data.request.safeParse(payload);
|
||||||
|
|
|
||||||
|
|
@ -163,18 +163,18 @@ Generated from bun.lock and installed packages in workspace node_modules folders
|
||||||
- Folder: `licenses/@tauri-apps_plugin-opener@2.5.4`
|
- Folder: `licenses/@tauri-apps_plugin-opener@2.5.4`
|
||||||
- Source package dir: `apps/tauri/node_modules/@tauri-apps/plugin-opener`
|
- Source package dir: `apps/tauri/node_modules/@tauri-apps/plugin-opener`
|
||||||
|
|
||||||
## @tensamin/ttp-core@0.0.15
|
## @tensamin/ttp-core@0.0.19
|
||||||
|
|
||||||
- License: UNKNOWN
|
- License: UNKNOWN
|
||||||
- Included files: LICENSE
|
- Included files: LICENSE
|
||||||
- Folder: `licenses/@tensamin_ttp-core@0.0.15`
|
- Folder: `licenses/@tensamin_ttp-core@0.0.19`
|
||||||
- Source package dir: `packages/ttp/node_modules/@tensamin/ttp-core`
|
- Source package dir: `packages/ttp/node_modules/@tensamin/ttp-core`
|
||||||
|
|
||||||
## @tensamin/ui@0.0.30
|
## @tensamin/ui@0.0.34
|
||||||
|
|
||||||
- License: UNKNOWN
|
- License: UNKNOWN
|
||||||
- Included files: none found
|
- Included files: none found
|
||||||
- Folder: `licenses/@tensamin_ui@0.0.30`
|
- Folder: `licenses/@tensamin_ui@0.0.34`
|
||||||
- Source package dir: `apps/tauri/node_modules/@tensamin/ui`
|
- Source package dir: `apps/tauri/node_modules/@tensamin/ui`
|
||||||
|
|
||||||
## @types/node@25.6.0
|
## @types/node@25.6.0
|
||||||
|
|
@ -449,6 +449,16 @@ Generated from bun.lock and installed packages in workspace node_modules folders
|
||||||
- Folder: `licenses/tailwindcss@4.2.4`
|
- Folder: `licenses/tailwindcss@4.2.4`
|
||||||
- Source package dir: `apps/web/node_modules/tailwindcss`
|
- Source package dir: `apps/web/node_modules/tailwindcss`
|
||||||
|
|
||||||
|
## tauri-plugin-app-events-api@0.2.0
|
||||||
|
|
||||||
|
- License: MIT
|
||||||
|
- Homepage: https://github.com/wtto00/tauri-plugin-app-events#readme
|
||||||
|
- Repository: git+https://github.com/wtto00/tauri-plugin-app-events.git
|
||||||
|
- Description: A plugin for tauri@v2 to listen some events on iOS and Android.
|
||||||
|
- Included files: LICENSE
|
||||||
|
- Folder: `licenses/tauri-plugin-app-events-api@0.2.0`
|
||||||
|
- Source package dir: `apps/web/node_modules/tauri-plugin-app-events-api`
|
||||||
|
|
||||||
## tw-animate-css@1.4.0
|
## tw-animate-css@1.4.0
|
||||||
|
|
||||||
- License: MIT
|
- License: MIT
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
"specVersion": "1.5",
|
"specVersion": "1.5",
|
||||||
"version": 1,
|
"version": 1,
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"timestamp": "2026-05-04T13:05:17.472Z",
|
"timestamp": "2026-05-21T10:15:15.541Z",
|
||||||
"tools": [
|
"tools": [
|
||||||
{
|
{
|
||||||
"vendor": "OpenAI",
|
"vendor": "OpenAI",
|
||||||
|
|
@ -580,15 +580,15 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"bomRef": "pkg:npm/%40tensamin/ttp-core@0.0.15",
|
"bomRef": "pkg:npm/%40tensamin/ttp-core@0.0.19",
|
||||||
"name": "@tensamin/ttp-core",
|
"name": "@tensamin/ttp-core",
|
||||||
"version": "0.0.15",
|
"version": "0.0.19",
|
||||||
"purl": "pkg:npm/%40tensamin/ttp-core@0.0.15",
|
"purl": "pkg:npm/%40tensamin/ttp-core@0.0.19",
|
||||||
"externalReferences": [],
|
"externalReferences": [],
|
||||||
"properties": [
|
"properties": [
|
||||||
{
|
{
|
||||||
"name": "local:licenseFolder",
|
"name": "local:licenseFolder",
|
||||||
"value": "licenses/@tensamin_ttp-core@0.0.15"
|
"value": "licenses/@tensamin_ttp-core@0.0.19"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "local:sourcePackageDir",
|
"name": "local:sourcePackageDir",
|
||||||
|
|
@ -598,15 +598,15 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"bomRef": "pkg:npm/%40tensamin/ui@0.0.30",
|
"bomRef": "pkg:npm/%40tensamin/ui@0.0.34",
|
||||||
"name": "@tensamin/ui",
|
"name": "@tensamin/ui",
|
||||||
"version": "0.0.30",
|
"version": "0.0.34",
|
||||||
"purl": "pkg:npm/%40tensamin/ui@0.0.30",
|
"purl": "pkg:npm/%40tensamin/ui@0.0.34",
|
||||||
"externalReferences": [],
|
"externalReferences": [],
|
||||||
"properties": [
|
"properties": [
|
||||||
{
|
{
|
||||||
"name": "local:licenseFolder",
|
"name": "local:licenseFolder",
|
||||||
"value": "licenses/@tensamin_ui@0.0.30"
|
"value": "licenses/@tensamin_ui@0.0.34"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "local:sourcePackageDir",
|
"name": "local:sourcePackageDir",
|
||||||
|
|
@ -1562,6 +1562,41 @@
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"type": "library",
|
||||||
|
"bomRef": "pkg:npm/tauri-plugin-app-events-api@0.2.0",
|
||||||
|
"name": "tauri-plugin-app-events-api",
|
||||||
|
"version": "0.2.0",
|
||||||
|
"purl": "pkg:npm/tauri-plugin-app-events-api@0.2.0",
|
||||||
|
"description": "A plugin for tauri@v2 to listen some events on iOS and Android.",
|
||||||
|
"licenses": [
|
||||||
|
{
|
||||||
|
"license": {
|
||||||
|
"id": "MIT"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"externalReferences": [
|
||||||
|
{
|
||||||
|
"type": "website",
|
||||||
|
"url": "https://github.com/wtto00/tauri-plugin-app-events#readme"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "vcs",
|
||||||
|
"url": "git+https://github.com/wtto00/tauri-plugin-app-events.git"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"properties": [
|
||||||
|
{
|
||||||
|
"name": "local:licenseFolder",
|
||||||
|
"value": "licenses/tauri-plugin-app-events-api@0.2.0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "local:sourcePackageDir",
|
||||||
|
"value": "apps/web/node_modules/tauri-plugin-app-events-api"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"bomRef": "pkg:npm/tw-animate-css@1.4.0",
|
"bomRef": "pkg:npm/tw-animate-css@1.4.0",
|
||||||
|
|
|
||||||
21
licenses/tauri-plugin-app-events-api@0.2.0/LICENSE
Normal file
21
licenses/tauri-plugin-app-events-api@0.2.0/LICENSE
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2024 简静凡
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"generatedAt": "2026-05-04T13:05:17.471Z",
|
"generatedAt": "2026-05-21T10:15:15.540Z",
|
||||||
"packageCount": 53,
|
"packageCount": 54,
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "@codemirror/commands",
|
"name": "@codemirror/commands",
|
||||||
|
|
@ -227,7 +227,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "@tensamin/ttp-core",
|
"name": "@tensamin/ttp-core",
|
||||||
"version": "0.0.15",
|
"version": "0.0.19",
|
||||||
"license": "UNKNOWN",
|
"license": "UNKNOWN",
|
||||||
"homepage": null,
|
"homepage": null,
|
||||||
"repository": null,
|
"repository": null,
|
||||||
|
|
@ -235,18 +235,18 @@
|
||||||
"files": [
|
"files": [
|
||||||
"LICENSE"
|
"LICENSE"
|
||||||
],
|
],
|
||||||
"licenseFolder": "licenses/@tensamin_ttp-core@0.0.15",
|
"licenseFolder": "licenses/@tensamin_ttp-core@0.0.19",
|
||||||
"sourcePackageDir": "packages/ttp/node_modules/@tensamin/ttp-core"
|
"sourcePackageDir": "packages/ttp/node_modules/@tensamin/ttp-core"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "@tensamin/ui",
|
"name": "@tensamin/ui",
|
||||||
"version": "0.0.30",
|
"version": "0.0.34",
|
||||||
"license": "UNKNOWN",
|
"license": "UNKNOWN",
|
||||||
"homepage": null,
|
"homepage": null,
|
||||||
"repository": null,
|
"repository": null,
|
||||||
"description": null,
|
"description": null,
|
||||||
"files": [],
|
"files": [],
|
||||||
"licenseFolder": "licenses/@tensamin_ui@0.0.30",
|
"licenseFolder": "licenses/@tensamin_ui@0.0.34",
|
||||||
"sourcePackageDir": "apps/tauri/node_modules/@tensamin/ui"
|
"sourcePackageDir": "apps/tauri/node_modules/@tensamin/ui"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -614,6 +614,19 @@
|
||||||
"licenseFolder": "licenses/tailwindcss@4.2.4",
|
"licenseFolder": "licenses/tailwindcss@4.2.4",
|
||||||
"sourcePackageDir": "apps/web/node_modules/tailwindcss"
|
"sourcePackageDir": "apps/web/node_modules/tailwindcss"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "tauri-plugin-app-events-api",
|
||||||
|
"version": "0.2.0",
|
||||||
|
"license": "MIT",
|
||||||
|
"homepage": "https://github.com/wtto00/tauri-plugin-app-events#readme",
|
||||||
|
"repository": "git+https://github.com/wtto00/tauri-plugin-app-events.git",
|
||||||
|
"description": "A plugin for tauri@v2 to listen some events on iOS and Android.",
|
||||||
|
"files": [
|
||||||
|
"LICENSE"
|
||||||
|
],
|
||||||
|
"licenseFolder": "licenses/tauri-plugin-app-events-api@0.2.0",
|
||||||
|
"sourcePackageDir": "apps/web/node_modules/tauri-plugin-app-events-api"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "tw-animate-css",
|
"name": "tw-animate-css",
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "tensamin",
|
"name": "tensamin",
|
||||||
"version": "0.0.1",
|
"version": "0.0.2",
|
||||||
"private": true,
|
"private": true,
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*",
|
"packages/*",
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,8 @@ export const ttp = {
|
||||||
},
|
},
|
||||||
get_user_data: {
|
get_user_data: {
|
||||||
request: z.object({
|
request: z.object({
|
||||||
user_id: z.number(),
|
user_id: z.number().optional(),
|
||||||
|
username: z.string().optional(),
|
||||||
}),
|
}),
|
||||||
response: user,
|
response: user,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ interface SessionContextType {
|
||||||
communities: Communities;
|
communities: Communities;
|
||||||
calls: Calls;
|
calls: Calls;
|
||||||
moveUserIdToTop: (userId: number) => void;
|
moveUserIdToTop: (userId: number) => void;
|
||||||
|
insertContact: (userId: number) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const SessionContext = createContext<SessionContextType | undefined>(undefined);
|
const SessionContext = createContext<SessionContextType | undefined>(undefined);
|
||||||
|
|
@ -69,9 +70,31 @@ export default function SessionProvider({ children }: { children: ReactNode }) {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const insertContact = (userId: number) => {
|
||||||
|
setContacts((prevContacts) => {
|
||||||
|
if (prevContacts.some((contact) => contact.user_id === userId)) {
|
||||||
|
return prevContacts;
|
||||||
|
}
|
||||||
|
|
||||||
|
const newUser = {
|
||||||
|
user_id: userId,
|
||||||
|
last_message_at: new Date().getTime(),
|
||||||
|
messages: [],
|
||||||
|
} satisfies Contacts[0];
|
||||||
|
|
||||||
|
return [newUser, ...prevContacts];
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SessionContext.Provider
|
<SessionContext.Provider
|
||||||
value={{ contacts, communities, calls: freshCalls, moveUserIdToTop }}
|
value={{
|
||||||
|
contacts,
|
||||||
|
communities,
|
||||||
|
calls: freshCalls,
|
||||||
|
moveUserIdToTop,
|
||||||
|
insertContact,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</SessionContext.Provider>
|
</SessionContext.Provider>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue