diff --git a/src/app/services/auth.js b/src/app/services/auth.js index 9fc537f6..e19b1789 100644 --- a/src/app/services/auth.js +++ b/src/app/services/auth.js @@ -1,44 +1,46 @@ -import { createApi } from '@reduxjs/toolkit/query/react'; -import baseQuery from './base.query'; +import { createApi } from "@reduxjs/toolkit/query/react"; +import baseQuery from "./base.query"; +import BASE_URL from "../config"; export const authApi = createApi({ - reducerPath: 'auth', - baseQuery, - endpoints: (builder) => ({ - login: builder.mutation({ - query: (credentials) => ({ - url: 'token/login', - method: 'POST', - body: { credential: credentials, device: 'web', device_token: 'test' } - }) - // transformResponse: (resp) => { - // console.log("resp", resp); - // if (resp.status == 401) { - // resp.msg = "username or password incorrect"; - // } - // return resp; - // }, + reducerPath: "auth", + baseQuery, + endpoints: (builder) => ({ + login: builder.mutation({ + query: (credentials) => ({ + url: "token/login", + method: "POST", + body: { credential: credentials, device: "web", device_token: "test" }, + }), + transformResponse: (data) => { + const { avatar_updated_at } = data.user; + data.user.avatar = + avatar_updated_at == 0 + ? "" + : `${BASE_URL}/resource/avatar?uid=${data.user.uid}`; + return data; + }, + }), + checkInviteTokenValid: builder.mutation({ + query: (token) => ({ + url: "user/check_invite_magic_token", + method: "POST", + body: { magic_token: token }, + }), + }), + getMetamaskNonce: builder.query({ + query: (address) => ({ + url: `/token/metamask/nonce?public_address=${address}`, + }), + }), + logout: builder.query({ + query: () => ({ url: `token/logout` }), + }), }), - checkInviteTokenValid: builder.mutation({ - query: (token) => ({ - url: 'user/check_invite_magic_token', - method: 'POST', - body: { magic_token: token } - }) - }), - getMetamaskNonce: builder.query({ - query: (address) => ({ - url: `/token/metamask/nonce?public_address=${address}` - }) - }), - logout: builder.query({ - query: () => ({ url: `token/logout` }) - }) - }) }); export const { - useLazyGetMetamaskNonceQuery, - useLoginMutation, - useLazyLogoutQuery, - useCheckInviteTokenValidMutation + useLazyGetMetamaskNonceQuery, + useLoginMutation, + useLazyLogoutQuery, + useCheckInviteTokenValidMutation, } = authApi; diff --git a/src/app/services/contact.js b/src/app/services/contact.js index 0be7a14b..1a8b3197 100644 --- a/src/app/services/contact.js +++ b/src/app/services/contact.js @@ -1,45 +1,52 @@ -import { createApi } from '@reduxjs/toolkit/query/react'; -import baseQuery from './base.query'; -import BASE_URL, { ContentTypes } from '../config'; -import { REHYDRATE } from 'redux-persist'; +import { createApi } from "@reduxjs/toolkit/query/react"; +import baseQuery from "./base.query"; +import BASE_URL, { ContentTypes } from "../config"; +import { REHYDRATE } from "redux-persist"; export const contactApi = createApi({ - reducerPath: 'contact', - baseQuery, - extractRehydrationInfo(action, { reducerPath }) { - if (action.type === REHYDRATE) { - return action.payload ? action.payload[reducerPath] : undefined; - } - }, - endpoints: (builder) => ({ - getContacts: builder.query({ - query: () => ({ url: `user` }), - transformResponse: (data) => { - return data.map((user) => { - const avatar = `${BASE_URL}/resource/avatar?uid=${user.uid}`; - user.avatar = avatar; - return user; - }); - } + reducerPath: "contact", + baseQuery, + extractRehydrationInfo(action, { reducerPath }) { + if (action.type === REHYDRATE) { + return action.payload ? action.payload[reducerPath] : undefined; + } + }, + endpoints: (builder) => ({ + getContacts: builder.query({ + query: () => ({ url: `user` }), + transformResponse: (data) => { + return data.map((user) => { + const avatar = + user.avatar_updated_at == 0 + ? "" + : `${BASE_URL}/resource/avatar?uid=${user.uid}`; + user.avatar = avatar; + return user; + }); + }, + }), + register: builder.mutation({ + query: (data) => ({ + url: `user/register`, + method: "POST", + body: data, + }), + }), + sendMsg: builder.mutation({ + query: ({ id, content, type = "text" }) => ({ + headers: { + "content-type": ContentTypes[type], + }, + url: `user/${id}/send`, + method: "POST", + body: content, + }), + }), }), - register: builder.mutation({ - query: (data) => ({ - url: `user/register`, - method: 'POST', - body: data - }) - }), - sendMsg: builder.mutation({ - query: ({ id, content, type = 'text' }) => ({ - headers: { - 'content-type': ContentTypes[type] - }, - url: `user/${id}/send`, - method: 'POST', - body: content - }) - }) - }) }); -export const { useGetContactsQuery, useSendMsgMutation, useRegisterMutation } = contactApi; +export const { + useGetContactsQuery, + useSendMsgMutation, + useRegisterMutation, +} = contactApi; diff --git a/src/common/component/Avatar.js b/src/common/component/Avatar.js index 3de37c73..1ebb198a 100644 --- a/src/common/component/Avatar.js +++ b/src/common/component/Avatar.js @@ -1,34 +1,59 @@ import { useState, useEffect } from "react"; -export default function Avatar({ url = "", id = 0, ...rest }) { +const initialAvatar = ({ + initials = "UK", + initial_size = 0, + size = 200, + foreground = "#fff", + background = "#4c99e9", + weight = 400, + fontFamily = "'Lato', 'Lato-Regular', 'Helvetica Neue'", +}) => { + const canvas = document.createElement("canvas"); + const width = size; + const height = size; + const devicePixelRatio = Math.max(window.devicePixelRatio, 1); + canvas.width = width * devicePixelRatio; + canvas.height = height * devicePixelRatio; + canvas.style.width = `${width}px`; + canvas.style.height = `${height}px`; + + const context = canvas.getContext("2d"); + context.scale(devicePixelRatio, devicePixelRatio); + context.rect(0, 0, canvas.width, canvas.height); + context.fillStyle = background; + context.fill(); + context.font = `${weight} ${initial_size || height / 2}px ${fontFamily}`; + context.textAlign = "center"; + context.textBaseline = "middle"; + context.fillStyle = foreground; + context.fillText(initials, width / 2, height / 2); + + /* istanbul ignore next */ + return canvas.toDataURL("image/png"); +}; +const getInitials = (name) => { + const arr = name.split(" ").filter((n) => !!n); + return arr + .map((t) => t[0]) + .join("") + .toUpperCase(); +}; +export default function Avatar({ url, name = "unkonw name", ...rest }) { const [src, setSrc] = useState(url); - const [loaded, setLoaded] = useState(false); - - const handleLoaded = () => { - setLoaded(true); - }; const handleError = () => { - if (src.indexOf("avatars.dicebear.com") > -1) return; - setSrc(`https://avatars.dicebear.com/api/adventurer-neutral/${id}.svg`); + const tmp = initialAvatar({ + initials: getInitials(name), + }); + setSrc(tmp); }; - useEffect(() => { - setLoaded(false); - setSrc(url); - }, [url]); + if (!url) { + const tmp = initialAvatar({ + initials: getInitials(name), + }); + setSrc(tmp); + } + }, [url, name]); - useEffect(() => { - const inter = setTimeout(() => { - if (!loaded) { - handleError(); - } - }, 2000); - - return () => { - clearTimeout(inter); - }; - }, [loaded]); - - return ( - - ); + return ; } diff --git a/src/common/component/Contact.js b/src/common/component/Contact.js index ae74d79e..89305974 100644 --- a/src/common/component/Contact.js +++ b/src/common/component/Contact.js @@ -1,9 +1,10 @@ // import React from 'react'; import styled from "styled-components"; -import Avatar from "./Avatar"; +import { useSelector } from "react-redux"; import Tippy from "@tippyjs/react"; +import "tippy.js/animations/scale-subtle.css"; +import Avatar from "./Avatar"; import Profile from "./Profile"; -import { useGetContactsQuery } from "../../app/services/contact"; const StyledWrapper = styled.div` display: flex; @@ -37,7 +38,9 @@ const StyledWrapper = styled.div` height: 10px; border-radius: 50%; outline: 2px solid #fff; - background-color: #22c55e; + &.online { + background-color: #22c55e; + } &.offline { background-color: #a1a1aa; } @@ -55,17 +58,17 @@ const StyledWrapper = styled.div` `; export default function Contact({ interactive = true, - status = "", uid = "", popover = false, }) { - const { data: contacts } = useGetContactsQuery(); + const contacts = useSelector((store) => store.contacts); if (!contacts) return null; const currUser = contacts.find((c) => c.uid == uid); return ( } >
- -
+ +
{currUser?.name} diff --git a/src/common/component/CurrentUser.js b/src/common/component/CurrentUser.js index a8636729..cd5aa432 100644 --- a/src/common/component/CurrentUser.js +++ b/src/common/component/CurrentUser.js @@ -59,15 +59,15 @@ export default function CurrentUser({ expand = true }) { }, [isSuccess]); if (!user) return null; - const { name, uid } = user; + const { name, avatar } = user; return (
diff --git a/src/common/component/Profile.js b/src/common/component/Profile.js index eb31c5ef..e1af5eff 100644 --- a/src/common/component/Profile.js +++ b/src/common/component/Profile.js @@ -67,7 +67,7 @@ export default function Profile({ data = null, type = "embed" }) { const { uid, name, email, avatar } = data; return ( - +

{name}

{email}
    diff --git a/src/routes/chat/DMList.js b/src/routes/chat/DMList.js index 85c79bf3..274893b3 100644 --- a/src/routes/chat/DMList.js +++ b/src/routes/chat/DMList.js @@ -31,7 +31,7 @@ const NavItem = ({ data, setFiles }) => { className={`session ${isActive ? "drop_over" : ""}`} to={`/chat/dm/${uid}`} > - +
    {user.name}