Squashed bugs
This commit is contained in:
parent
cbbadc9e67
commit
126f397d97
9 changed files with 44 additions and 43 deletions
|
|
@ -24,7 +24,6 @@
|
||||||
"noFallthroughCasesInSwitch": true,
|
"noFallthroughCasesInSwitch": true,
|
||||||
"noUncheckedSideEffectImports": true,
|
"noUncheckedSideEffectImports": true,
|
||||||
|
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
"paths": {
|
||||||
"@/*": ["./src/*"]
|
"@/*": ["./src/*"]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,10 @@ import globals from "globals";
|
||||||
import tseslint from "typescript-eslint";
|
import tseslint from "typescript-eslint";
|
||||||
import reactHooks from "eslint-plugin-react-hooks";
|
import reactHooks from "eslint-plugin-react-hooks";
|
||||||
import * as tsParser from "@typescript-eslint/parser";
|
import * as tsParser from "@typescript-eslint/parser";
|
||||||
|
import { dirname } from "node:path";
|
||||||
|
import { fileURLToPath } from "node:url";
|
||||||
|
|
||||||
|
const tsconfigRootDir = dirname(fileURLToPath(import.meta.url));
|
||||||
|
|
||||||
export default [
|
export default [
|
||||||
{
|
{
|
||||||
|
|
@ -14,6 +18,9 @@ export default [
|
||||||
files: ["**/*.{ts,tsx}"],
|
files: ["**/*.{ts,tsx}"],
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
parser: tsParser,
|
parser: tsParser,
|
||||||
|
parserOptions: {
|
||||||
|
tsconfigRootDir,
|
||||||
|
},
|
||||||
globals: {
|
globals: {
|
||||||
...globals.browser,
|
...globals.browser,
|
||||||
...globals.node,
|
...globals.node,
|
||||||
|
|
|
||||||
|
|
@ -74,7 +74,7 @@ export default function InputComponent({
|
||||||
const reference = addLiveMessage({
|
const reference = addLiveMessage({
|
||||||
height,
|
height,
|
||||||
not_encrypted: true,
|
not_encrypted: true,
|
||||||
timestamp: time,
|
send_time: time,
|
||||||
content: currentValue,
|
content: currentValue,
|
||||||
sent_by_self: true,
|
sent_by_self: true,
|
||||||
message_state: "awaiting",
|
message_state: "awaiting",
|
||||||
|
|
@ -86,13 +86,13 @@ export default function InputComponent({
|
||||||
height,
|
height,
|
||||||
content: encryptedContext,
|
content: encryptedContext,
|
||||||
receiver_id: userId,
|
receiver_id: userId,
|
||||||
timestamp: time,
|
send_time: time,
|
||||||
}).catch((e) => {
|
}).catch((e) => {
|
||||||
log(0, "Chat", "red", "Failed to send message", e, {
|
log(0, "Chat", "red", "Failed to send message", e, {
|
||||||
content: currentValue,
|
content: currentValue,
|
||||||
encryptedContext,
|
encryptedContext,
|
||||||
receiver_id: userId,
|
receiver_id: userId,
|
||||||
timestamp: time,
|
send_time: time,
|
||||||
});
|
});
|
||||||
reference.setFailed(true);
|
reference.setFailed(true);
|
||||||
toast("error", "Failed to send message");
|
toast("error", "Failed to send message");
|
||||||
|
|
@ -108,7 +108,7 @@ export default function InputComponent({
|
||||||
className={cn(
|
className={cn(
|
||||||
"rounded-none border-b-0 pt-0 pb-[env(safe-area-inset-bottom)]",
|
"rounded-none border-b-0 pt-0 pb-[env(safe-area-inset-bottom)]",
|
||||||
isMobile
|
isMobile
|
||||||
? "border-0 border-t-1 fixed w-full bottom-0 left-0 px-2"
|
? "border-0 border-t fixed w-full bottom-0 left-0 px-2"
|
||||||
: "rounded-t-xl",
|
: "rounded-t-xl",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
@ -123,7 +123,7 @@ export default function InputComponent({
|
||||||
message={{
|
message={{
|
||||||
height: 0,
|
height: 0,
|
||||||
not_encrypted: true,
|
not_encrypted: true,
|
||||||
timestamp: 0,
|
send_time: 0,
|
||||||
content: value,
|
content: value,
|
||||||
sent_by_self: true,
|
sent_by_self: true,
|
||||||
message_state: "awaiting",
|
message_state: "awaiting",
|
||||||
|
|
|
||||||
|
|
@ -157,7 +157,7 @@ export default React.memo(MessageComponent, (prev, next) => {
|
||||||
return (
|
return (
|
||||||
prev.notEncrypted === next.notEncrypted &&
|
prev.notEncrypted === next.notEncrypted &&
|
||||||
prev.measureRef === next.measureRef &&
|
prev.measureRef === next.measureRef &&
|
||||||
prev.message.timestamp === next.message.timestamp &&
|
prev.message.send_time === next.message.send_time &&
|
||||||
prev.message.content === next.message.content &&
|
prev.message.content === next.message.content &&
|
||||||
prev.message.height === next.message.height &&
|
prev.message.height === next.message.height &&
|
||||||
prev.message.sent_by_self === next.message.sent_by_self &&
|
prev.message.sent_by_self === next.message.sent_by_self &&
|
||||||
|
|
|
||||||
|
|
@ -22,17 +22,17 @@ export const context = createContext<contextType | undefined>(undefined);
|
||||||
|
|
||||||
const queryClient = new QueryClient();
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
function updateMessageStateByTimestamp<
|
function updateMessageStateBySendTime<
|
||||||
T extends { timestamp: number; message_state: RawMessage["message_state"] },
|
T extends { send_time: number; message_state: RawMessage["message_state"] },
|
||||||
>(
|
>(
|
||||||
messages: T[],
|
messages: T[],
|
||||||
timestamp: number,
|
sendTime: number,
|
||||||
messageState: RawMessage["message_state"],
|
messageState: RawMessage["message_state"],
|
||||||
): { next: T[]; updated: boolean } {
|
): { next: T[]; updated: boolean } {
|
||||||
let updated = false;
|
let updated = false;
|
||||||
|
|
||||||
const next = messages.map((item) => {
|
const next = messages.map((item) => {
|
||||||
if (item.timestamp !== timestamp || item.message_state === messageState) {
|
if (item.send_time !== sendTime || item.message_state === messageState) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -54,7 +54,7 @@ function updateMessageStateByTimestamp<
|
||||||
* @param props Parameter props.
|
* @param props Parameter props.
|
||||||
* @returns unknown.
|
* @returns unknown.
|
||||||
*/
|
*/
|
||||||
export function Provider(props: { children: ReactNode }) {
|
export default function Provider(props: { children: ReactNode }) {
|
||||||
const { getSharedSecret } = useCrypto();
|
const { getSharedSecret } = useCrypto();
|
||||||
const { get } = useUser();
|
const { get } = useUser();
|
||||||
const { load } = useStorage();
|
const { load } = useStorage();
|
||||||
|
|
@ -141,14 +141,14 @@ export function Provider(props: { children: ReactNode }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const rawMessages = messages.data.messages;
|
const rawMessages = messages.data.messages;
|
||||||
const sorted = [...rawMessages].sort((a, b) => a.timestamp - b.timestamp);
|
const sorted = [...rawMessages].sort((a, b) => a.send_time - b.send_time);
|
||||||
|
|
||||||
if (sorted.length > 0) {
|
if (sorted.length > 0) {
|
||||||
const fetchedTimestamps = new Set(sorted.map((item) => item.timestamp));
|
const fetchedSendTimes = new Set(sorted.map((item) => item.send_time));
|
||||||
|
|
||||||
setLiveMessagesState((prev) => {
|
setLiveMessagesState((prev) => {
|
||||||
const filtered = prev.filter(
|
const filtered = prev.filter(
|
||||||
(liveMessage) => !fetchedTimestamps.has(liveMessage.timestamp),
|
(liveMessage) => !fetchedSendTimes.has(liveMessage.send_time),
|
||||||
);
|
);
|
||||||
|
|
||||||
return filtered.length === prev.length ? prev : filtered;
|
return filtered.length === prev.length ? prev : filtered;
|
||||||
|
|
@ -200,19 +200,19 @@ export function Provider(props: { children: ReactNode }) {
|
||||||
|
|
||||||
const rawData = message.data as {
|
const rawData = message.data as {
|
||||||
chat_partner_id: unknown;
|
chat_partner_id: unknown;
|
||||||
timestamp: unknown;
|
send_time: unknown;
|
||||||
message_state: RawMessage["message_state"];
|
message_state: RawMessage["message_state"];
|
||||||
};
|
};
|
||||||
|
|
||||||
const nextState = {
|
const nextState = {
|
||||||
chat_partner_id: Number(rawData.chat_partner_id),
|
chat_partner_id: Number(rawData.chat_partner_id),
|
||||||
timestamp: Number(rawData.timestamp),
|
send_time: Number(rawData.send_time),
|
||||||
message_state: rawData.message_state,
|
message_state: rawData.message_state,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!Number.isFinite(nextState.chat_partner_id) ||
|
!Number.isFinite(nextState.chat_partner_id) ||
|
||||||
!Number.isFinite(nextState.timestamp)
|
!Number.isFinite(nextState.send_time)
|
||||||
) {
|
) {
|
||||||
log(
|
log(
|
||||||
3,
|
3,
|
||||||
|
|
@ -238,9 +238,9 @@ export function Provider(props: { children: ReactNode }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
setLiveMessagesState((prev) => {
|
setLiveMessagesState((prev) => {
|
||||||
const { next, updated } = updateMessageStateByTimestamp(
|
const { next, updated } = updateMessageStateBySendTime(
|
||||||
prev,
|
prev,
|
||||||
nextState.timestamp,
|
nextState.send_time,
|
||||||
nextState.message_state,
|
nextState.message_state,
|
||||||
);
|
);
|
||||||
return updated ? next : prev;
|
return updated ? next : prev;
|
||||||
|
|
@ -257,9 +257,9 @@ export function Provider(props: { children: ReactNode }) {
|
||||||
let updated = false;
|
let updated = false;
|
||||||
|
|
||||||
const pages = current.pages.map((page) => {
|
const pages = current.pages.map((page) => {
|
||||||
const nextPage = updateMessageStateByTimestamp(
|
const nextPage = updateMessageStateBySendTime(
|
||||||
page,
|
page,
|
||||||
nextState.timestamp,
|
nextState.send_time,
|
||||||
nextState.message_state,
|
nextState.message_state,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -80,11 +80,11 @@ export default function Screen() {
|
||||||
return liveMessagesSnapshot;
|
return liveMessagesSnapshot;
|
||||||
}
|
}
|
||||||
|
|
||||||
const historicalTimestamps = new Set(
|
const historicalSendTimes = new Set(
|
||||||
historicalMessages.map((message) => message.timestamp),
|
historicalMessages.map((message) => message.send_time),
|
||||||
);
|
);
|
||||||
const liveWithoutDuplicates = liveMessagesSnapshot.filter(
|
const liveWithoutDuplicates = liveMessagesSnapshot.filter(
|
||||||
(message) => !historicalTimestamps.has(message.timestamp),
|
(message) => !historicalSendTimes.has(message.send_time),
|
||||||
);
|
);
|
||||||
|
|
||||||
return [...historicalMessages, ...liveWithoutDuplicates];
|
return [...historicalMessages, ...liveWithoutDuplicates];
|
||||||
|
|
@ -97,7 +97,7 @@ export default function Screen() {
|
||||||
}, [messages]);
|
}, [messages]);
|
||||||
|
|
||||||
const getItemKey = React.useCallback((index: number) => {
|
const getItemKey = React.useCallback((index: number) => {
|
||||||
return messagesRef.current[index]?.timestamp ?? index;
|
return messagesRef.current[index]?.send_time ?? index;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// eslint-disable-next-line react-hooks/incompatible-library
|
// eslint-disable-next-line react-hooks/incompatible-library
|
||||||
|
|
@ -167,7 +167,11 @@ export default function Screen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
setLastLiveMessageCount(count);
|
setLastLiveMessageCount(count);
|
||||||
}, [lastLiveMessageCount, liveMessagesSnapshot.length, stickyBottomThreshold]);
|
}, [
|
||||||
|
lastLiveMessageCount,
|
||||||
|
liveMessagesSnapshot.length,
|
||||||
|
stickyBottomThreshold,
|
||||||
|
]);
|
||||||
|
|
||||||
React.useLayoutEffect(() => {
|
React.useLayoutEffect(() => {
|
||||||
if (
|
if (
|
||||||
|
|
@ -291,7 +295,7 @@ export default function Screen() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={message.timestamp}
|
key={message.send_time}
|
||||||
data-index={virtualRow.index}
|
data-index={virtualRow.index}
|
||||||
ref={virtualizer.measureElement}
|
ref={virtualizer.measureElement}
|
||||||
style={{
|
style={{
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ const message = z.object({
|
||||||
height: z.number(),
|
height: z.number(),
|
||||||
not_encrypted: z.boolean().optional(),
|
not_encrypted: z.boolean().optional(),
|
||||||
sent_by_self: z.boolean(),
|
sent_by_self: z.boolean(),
|
||||||
timestamp: z.number(),
|
send_time: z.number(),
|
||||||
content: z.base64(),
|
content: z.base64(),
|
||||||
files: z.array(fileFromMessage).optional(),
|
files: z.array(fileFromMessage).optional(),
|
||||||
tint: z.string().length(7).startsWith("#").optional(),
|
tint: z.string().length(7).startsWith("#").optional(),
|
||||||
|
|
@ -111,7 +111,7 @@ export const ttp = {
|
||||||
request: z.object({}),
|
request: z.object({}),
|
||||||
response: z.object({
|
response: z.object({
|
||||||
sender_id: z.number(),
|
sender_id: z.number(),
|
||||||
timestamp: z.number(),
|
send_time: z.number(),
|
||||||
message,
|
message,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|
@ -130,7 +130,7 @@ export const ttp = {
|
||||||
height: z.number(),
|
height: z.number(),
|
||||||
content: z.base64(),
|
content: z.base64(),
|
||||||
receiver_id: z.number(),
|
receiver_id: z.number(),
|
||||||
timestamp: z.number(),
|
send_time: z.number(),
|
||||||
files: z.array(fileFromMessage).optional(),
|
files: z.array(fileFromMessage).optional(),
|
||||||
}),
|
}),
|
||||||
response: z.object({}),
|
response: z.object({}),
|
||||||
|
|
@ -145,13 +145,13 @@ export const ttp = {
|
||||||
message_state: {
|
message_state: {
|
||||||
request: z.object({
|
request: z.object({
|
||||||
chat_partner_id: z.number(),
|
chat_partner_id: z.number(),
|
||||||
timestamp: z.number(),
|
send_time: z.number(),
|
||||||
message_state: message.shape.message_state,
|
message_state: message.shape.message_state,
|
||||||
}),
|
}),
|
||||||
response: z.object({
|
response: z.object({
|
||||||
chat_partner_id: z.number(),
|
chat_partner_id: z.number(),
|
||||||
message_state: message.shape.message_state,
|
message_state: message.shape.message_state,
|
||||||
timestamp: z.number(),
|
send_time: z.number(),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,7 @@ const TTPContext = createContext<ContextType | undefined>(undefined);
|
||||||
* @param props Component props with children.
|
* @param props Component props with children.
|
||||||
* @returns Loading, error, or provider-wrapped JSX.
|
* @returns Loading, error, or provider-wrapped JSX.
|
||||||
*/
|
*/
|
||||||
export default function Provider(props: {
|
export function Provider(props: {
|
||||||
children: ReactNode;
|
children: ReactNode;
|
||||||
blockConnection?: boolean;
|
blockConnection?: boolean;
|
||||||
}) {
|
}) {
|
||||||
|
|
|
||||||
|
|
@ -1,9 +0,0 @@
|
||||||
{
|
|
||||||
"compilerOptions": {
|
|
||||||
"module": "esnext",
|
|
||||||
"baseUrl": ".",
|
|
||||||
"paths": {
|
|
||||||
"@app/*": ["packages/*/src", "apps/*/src"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in a new issue