From cd3447851a990fd393b7f9ce64c24933bf631830 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Thu, 7 Sep 2023 16:04:08 +0530 Subject: [PATCH 01/11] fix: add cursor pointers to the icon buttons --- .../react/components/organization/domain/add-domain.tsx | 1 + .../components/organization/domain/verify-domain.tsx | 1 + .../react/components/organization/general/delete.tsx | 1 + .../react/components/organization/members/invite.tsx | 1 + .../core/react/components/organization/project/add.tsx | 9 +++++++-- .../react/components/organization/project/delete.tsx | 9 +++++++-- .../core/react/components/organization/teams/add.tsx | 1 + .../core/react/components/organization/teams/delete.tsx | 3 ++- sdks/js/packages/core/react/components/window/index.tsx | 4 ++-- 9 files changed, 23 insertions(+), 7 deletions(-) diff --git a/sdks/js/packages/core/react/components/organization/domain/add-domain.tsx b/sdks/js/packages/core/react/components/organization/domain/add-domain.tsx index 39344693a..2ab511476 100644 --- a/sdks/js/packages/core/react/components/organization/domain/add-domain.tsx +++ b/sdks/js/packages/core/react/components/organization/domain/add-domain.tsx @@ -71,6 +71,7 @@ export const AddDomain = () => { cross navigate({ to: '/domains' })} diff --git a/sdks/js/packages/core/react/components/organization/domain/verify-domain.tsx b/sdks/js/packages/core/react/components/organization/domain/verify-domain.tsx index 20518ce0c..1ab4d4504 100644 --- a/sdks/js/packages/core/react/components/organization/domain/verify-domain.tsx +++ b/sdks/js/packages/core/react/components/organization/domain/verify-domain.tsx @@ -74,6 +74,7 @@ export const VerifyDomain = () => { cross navigate({ to: '/domains' })} diff --git a/sdks/js/packages/core/react/components/organization/general/delete.tsx b/sdks/js/packages/core/react/components/organization/general/delete.tsx index 962583d8f..3f801bcf1 100644 --- a/sdks/js/packages/core/react/components/organization/general/delete.tsx +++ b/sdks/js/packages/core/react/components/organization/general/delete.tsx @@ -71,6 +71,7 @@ export const DeleteOrganization = () => { cross navigate({ to: '/' })} diff --git a/sdks/js/packages/core/react/components/organization/members/invite.tsx b/sdks/js/packages/core/react/components/organization/members/invite.tsx index c7548d604..421bc7421 100644 --- a/sdks/js/packages/core/react/components/organization/members/invite.tsx +++ b/sdks/js/packages/core/react/components/organization/members/invite.tsx @@ -101,6 +101,7 @@ export const InviteMember = () => { cross navigate({ to: '/members' })} diff --git a/sdks/js/packages/core/react/components/organization/project/add.tsx b/sdks/js/packages/core/react/components/organization/project/add.tsx index 4f2ba6c35..a25193183 100644 --- a/sdks/js/packages/core/react/components/organization/project/add.tsx +++ b/sdks/js/packages/core/react/components/organization/project/add.tsx @@ -64,8 +64,13 @@ export const AddProject = () => { Add Project - {/* @ts-ignore */} - cross navigate('/members')} /> + cross navigate({ to: '/members' })} + style={{ cursor: 'pointer' }} + />
diff --git a/sdks/js/packages/core/react/components/organization/project/delete.tsx b/sdks/js/packages/core/react/components/organization/project/delete.tsx index 9a208659f..85dd2bd14 100644 --- a/sdks/js/packages/core/react/components/organization/project/delete.tsx +++ b/sdks/js/packages/core/react/components/organization/project/delete.tsx @@ -89,8 +89,13 @@ export const DeleteProject = () => { Verify project deletion - {/* @ts-ignore */} - cross navigate('/')} /> + cross navigate({ to: '/' })} + style={{ cursor: 'pointer' }} + /> diff --git a/sdks/js/packages/core/react/components/organization/teams/add.tsx b/sdks/js/packages/core/react/components/organization/teams/add.tsx index 4b44f5548..556935403 100644 --- a/sdks/js/packages/core/react/components/organization/teams/add.tsx +++ b/sdks/js/packages/core/react/components/organization/teams/add.tsx @@ -64,6 +64,7 @@ export const AddTeam = () => { // @ts-ignore src={cross} onClick={() => navigate({ to: '/teams' })} + style={{ cursor: 'pointer' }} /> diff --git a/sdks/js/packages/core/react/components/organization/teams/delete.tsx b/sdks/js/packages/core/react/components/organization/teams/delete.tsx index 04f994318..9fc1df226 100644 --- a/sdks/js/packages/core/react/components/organization/teams/delete.tsx +++ b/sdks/js/packages/core/react/components/organization/teams/delete.tsx @@ -89,9 +89,10 @@ export const DeleteTeam = () => { cross navigate({ to: '/teams' })} + style={{ cursor: 'pointer' }} /> diff --git a/sdks/js/packages/core/react/components/window/index.tsx b/sdks/js/packages/core/react/components/window/index.tsx index 171c26c89..c76ae0974 100644 --- a/sdks/js/packages/core/react/components/window/index.tsx +++ b/sdks/js/packages/core/react/components/window/index.tsx @@ -14,8 +14,6 @@ interface WindowProps extends React.HTMLAttributes { children?: React.ReactNode; } - - export const Window = ({ open = false, onOpenChange, @@ -49,6 +47,7 @@ export const Window = ({ // @ts-ignore src={isCloseActive ? closeClose : closeDefault} onClick={() => onOpenChange && onOpenChange(false)} + style={{ cursor: 'pointer' }} /> setZoomActive(true)} @@ -63,6 +62,7 @@ export const Window = ({ : resizeDefault } onClick={() => setZoom(!zoom)} + style={{ cursor: 'pointer' }} /> From 9d3f0fd27c5b32311d197b938fffad8fc101302d Mon Sep 17 00:00:00 2001 From: Rishabh Date: Thu, 7 Sep 2023 16:04:25 +0530 Subject: [PATCH 02/11] chore: add react-loading-skeleton --- sdks/js/packages/core/package.json | 1 + sdks/js/packages/core/react/index.ts | 2 +- sdks/js/pnpm-lock.yaml | 11 +++++++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/sdks/js/packages/core/package.json b/sdks/js/packages/core/package.json index 8d998730b..04a8be972 100644 --- a/sdks/js/packages/core/package.json +++ b/sdks/js/packages/core/package.json @@ -73,6 +73,7 @@ "axios": "^1.4.0", "class-variance-authority": "^0.7.0", "react-hook-form": "^7.45.2", + "react-loading-skeleton": "^3.3.1", "sonner": "^0.6.2", "yup": "^1.2.0" }, diff --git a/sdks/js/packages/core/react/index.ts b/sdks/js/packages/core/react/index.ts index d6afa5016..705ebc8f9 100644 --- a/sdks/js/packages/core/react/index.ts +++ b/sdks/js/packages/core/react/index.ts @@ -1,4 +1,5 @@ import '@raystack/apsara/index.css'; +import 'react-loading-skeleton/dist/skeleton.css'; export { Container } from './components/Container'; export { Header } from './components/Header'; @@ -11,4 +12,3 @@ export { Window } from './components/window'; export { useFrontier } from './contexts/FrontierContext'; export { FrontierProvider } from './contexts/FrontierProvider'; - diff --git a/sdks/js/pnpm-lock.yaml b/sdks/js/pnpm-lock.yaml index 1d22b0ece..9fdc51e93 100644 --- a/sdks/js/pnpm-lock.yaml +++ b/sdks/js/pnpm-lock.yaml @@ -54,6 +54,9 @@ importers: react-hook-form: specifier: ^7.45.2 version: 7.45.2(react@18.2.0) + react-loading-skeleton: + specifier: ^3.3.1 + version: 3.3.1(react@18.2.0) sonner: specifier: ^0.6.2 version: 0.6.2(react-dom@18.2.0)(react@18.2.0) @@ -5457,6 +5460,14 @@ packages: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} dev: false + /react-loading-skeleton@3.3.1(react@18.2.0): + resolution: {integrity: sha512-NilqqwMh2v9omN7LteiDloEVpFyMIa0VGqF+ukqp0ncVlYu1sKYbYGX9JEl+GtOT9TKsh04zCHAbavnQ2USldA==} + peerDependencies: + react: '>=16.8.0' + dependencies: + react: 18.2.0 + dev: false + /react@18.2.0: resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} engines: {node: '>=0.10.0'} From faabea0091f6be45d20bd572aa28c3687682be76 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Thu, 7 Sep 2023 16:04:47 +0530 Subject: [PATCH 03/11] chore: add isActiveOrganizationLoading in context --- .../react/components/organization/profile.tsx | 27 ++++++++++++++----- .../core/react/contexts/FrontierContext.tsx | 14 ++++++++-- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/sdks/js/packages/core/react/components/organization/profile.tsx b/sdks/js/packages/core/react/components/organization/profile.tsx index fca38291c..df377b254 100644 --- a/sdks/js/packages/core/react/components/organization/profile.tsx +++ b/sdks/js/packages/core/react/components/organization/profile.tsx @@ -174,15 +174,28 @@ export const OrganizationProfile = ({ organizationId, defaultRoute = '/' }: OrganizationProfileProps) => { - const { client, setActiveOrganization } = useFrontier(); + const { client, setActiveOrganization, setIsActiveOrganizationLoading } = + useFrontier(); const fetchOrganization = useCallback(async () => { - const { - // @ts-ignore - data: { organization } - } = await client?.frontierServiceGetOrganization(organizationId); - setActiveOrganization(organization); - }, [client, organizationId, setActiveOrganization]); + try { + setIsActiveOrganizationLoading(true); + const { + // @ts-ignore + data: { organization } + } = await client?.frontierServiceGetOrganization(organizationId); + setActiveOrganization(organization); + } catch (err) { + console.error(err); + } finally { + setIsActiveOrganizationLoading(false); + } + }, [ + client, + organizationId, + setActiveOrganization, + setIsActiveOrganizationLoading + ]); useEffect(() => { if (organizationId) { diff --git a/sdks/js/packages/core/react/contexts/FrontierContext.tsx b/sdks/js/packages/core/react/contexts/FrontierContext.tsx index 089394bff..e544f5c84 100644 --- a/sdks/js/packages/core/react/contexts/FrontierContext.tsx +++ b/sdks/js/packages/core/react/contexts/FrontierContext.tsx @@ -40,6 +40,9 @@ interface FrontierContextProviderProps { setActiveOrganization: Dispatch< SetStateAction >; + + isActiveOrganizationLoading: boolean; + setIsActiveOrganizationLoading: Dispatch>; } const defaultConfig = { @@ -67,7 +70,10 @@ const initialValues: FrontierContextProviderProps = { setUser: () => undefined, activeOrganization: undefined, - setActiveOrganization: () => undefined + setActiveOrganization: () => undefined, + + isActiveOrganizationLoading: false, + setIsActiveOrganizationLoading: () => undefined }; export const FrontierContext = @@ -88,6 +94,8 @@ export const FrontierContextProvider = ({ const [user, setUser] = useState(); const [activeOrganization, setActiveOrganization] = useState(); + const [isActiveOrganizationLoading, setIsActiveOrganizationLoading] = + useState(false); useEffect(() => { async function getFrontierInformation() { @@ -173,7 +181,9 @@ export const FrontierContextProvider = ({ user, setUser, activeOrganization, - setActiveOrganization + setActiveOrganization, + isActiveOrganizationLoading, + setIsActiveOrganizationLoading }} > {children} From a30dcd8b2b8c0d7ed535dd0e3f24c631421f5c3c Mon Sep 17 00:00:00 2001 From: Rishabh Date: Thu, 7 Sep 2023 16:05:25 +0530 Subject: [PATCH 04/11] feat: show loader in general org page --- .../organization/general/general.profile.tsx | 29 +++++--- .../general/general.workspace.tsx | 66 +++++++++++-------- .../components/organization/general/index.tsx | 21 ++++-- 3 files changed, 74 insertions(+), 42 deletions(-) diff --git a/sdks/js/packages/core/react/components/organization/general/general.profile.tsx b/sdks/js/packages/core/react/components/organization/general/general.profile.tsx index 19506e2f5..6f07ece3a 100644 --- a/sdks/js/packages/core/react/components/organization/general/general.profile.tsx +++ b/sdks/js/packages/core/react/components/organization/general/general.profile.tsx @@ -1,27 +1,36 @@ 'use client'; import { Avatar, Flex, Text } from '@raystack/apsara'; +import Skeleton from 'react-loading-skeleton'; // @ts-ignore import { V1Beta1Organization } from '~/src'; import { getInitials } from '~/utils'; -import styles from './general.module.css'; +// import styles from './general.module.css'; interface GeneralProfileProps { organization?: V1Beta1Organization; + isLoading?: boolean; } -export const GeneralProfile = ({ organization }: GeneralProfileProps) => { +export const GeneralProfile = ({ + organization, + isLoading +}: GeneralProfileProps) => { return ( - - + {isLoading ? ( + + ) : ( + + )} + {/* Pick a logo for your organisation. Max size: 5 Mb - + */} ); }; diff --git a/sdks/js/packages/core/react/components/organization/general/general.workspace.tsx b/sdks/js/packages/core/react/components/organization/general/general.workspace.tsx index 8e231d88a..5dba186d2 100644 --- a/sdks/js/packages/core/react/components/organization/general/general.workspace.tsx +++ b/sdks/js/packages/core/react/components/organization/general/general.workspace.tsx @@ -9,6 +9,7 @@ import { } from '@raystack/apsara'; import { useEffect } from 'react'; import { Controller, useForm } from 'react-hook-form'; +import Skeleton from 'react-loading-skeleton'; import { toast } from 'sonner'; import * as yup from 'yup'; import { useFrontier } from '~/react/contexts/FrontierContext'; @@ -22,9 +23,11 @@ const generalSchema = yup .required(); export const GeneralOrganization = ({ - organization + organization, + isLoading }: { organization?: V1Beta1Organization; + isLoading?: boolean; }) => { const { client } = useFrontier(); const { @@ -60,19 +63,23 @@ export const GeneralOrganization = ({ - ( - - )} - defaultValue={organization?.title} - control={control} - name="title" - /> + {isLoading ? ( + + ) : ( + ( + + )} + defaultValue={organization?.title} + control={control} + name="title" + /> + )} {errors.title && String(errors.title?.message)} @@ -81,19 +88,23 @@ export const GeneralOrganization = ({ - ( - - )} - defaultValue={organization?.name} - control={control} - name="name" - /> + {isLoading ? ( + + ) : ( + ( + + )} + defaultValue={organization?.name} + control={control} + name="name" + /> + )} {errors.name && String(errors.name?.message)} @@ -105,6 +116,7 @@ export const GeneralOrganization = ({ variant="primary" type="submit" style={{ width: 'fit-content' }} + disabled={isLoading} > {isSubmitting ? 'updating...' : 'Update'} diff --git a/sdks/js/packages/core/react/components/organization/general/index.tsx b/sdks/js/packages/core/react/components/organization/general/index.tsx index be151b2f1..7de8aa38b 100644 --- a/sdks/js/packages/core/react/components/organization/general/index.tsx +++ b/sdks/js/packages/core/react/components/organization/general/index.tsx @@ -8,25 +8,35 @@ import { GeneralProfile } from './general.profile'; import { GeneralOrganization } from './general.workspace'; export default function GeneralSetting() { - const { activeOrganization: organization } = useFrontier(); + const { + activeOrganization: organization, + isActiveOrganizationLoading: isLoading + } = useFrontier(); return ( General - + - + - + ); } -export const GeneralDeleteOrganization = () => { +export const GeneralDeleteOrganization = ({ + isLoading +}: { + isLoading?: boolean; +}) => { const navigate = useNavigate({ from: '/' }); return ( @@ -39,6 +49,7 @@ export const GeneralDeleteOrganization = () => { type="submit" size="medium" onClick={() => navigate({ to: '/delete' })} + disabled={isLoading} > Delete organization From 5ab55429f84e6662a3cea9b266c9d5ef15d1d09a Mon Sep 17 00:00:00 2001 From: Rishabh Date: Thu, 7 Sep 2023 22:58:57 +0530 Subject: [PATCH 05/11] feat: show loader in members table --- .../components/organization/members/index.tsx | 74 +++++++++++------ .../organization/members/member.columns.tsx | 83 ++++++++++++------- .../organization/members/member.types.tsx | 3 +- 3 files changed, 104 insertions(+), 56 deletions(-) diff --git a/sdks/js/packages/core/react/components/organization/members/index.tsx b/sdks/js/packages/core/react/components/organization/members/index.tsx index 902cf9893..be3feda63 100644 --- a/sdks/js/packages/core/react/components/organization/members/index.tsx +++ b/sdks/js/packages/core/react/components/organization/members/index.tsx @@ -2,7 +2,7 @@ import { Button, DataTable, EmptyState, Flex, Text } from '@raystack/apsara'; import { Outlet, useNavigate, useRouterState } from '@tanstack/react-router'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { useFrontier } from '~/react/contexts/FrontierContext'; import { V1Beta1User } from '~/src'; import { styles } from '../styles'; @@ -11,30 +11,38 @@ import type { MembersTableType } from './member.types'; export default function WorkspaceMembers() { const [users, setUsers] = useState([]); + const [isUsersLoading, setIsUsersLoading] = useState(false); const { client, activeOrganization: organization } = useFrontier(); const routerState = useRouterState(); const fetchOrganizationUser = useCallback(async () => { if (!organization?.id) return; - const { - // @ts-ignore - data: { users } - } = await client?.frontierServiceListOrganizationUsers(organization?.id); - setUsers(users); + try { + setIsUsersLoading(true); + const { + // @ts-ignore + data: { users } + } = await client?.frontierServiceListOrganizationUsers(organization?.id); + setUsers(users); - const { - // @ts-ignore - data: { invitations } - } = await client?.frontierServiceListOrganizationInvitations( - organization?.id - ); + const { + // @ts-ignore + data: { invitations } + } = await client?.frontierServiceListOrganizationInvitations( + organization?.id + ); - const invitedUsers = invitations.map((user: V1Beta1User) => ({ - ...user, - invited: true - })); - // @ts-ignore - setUsers([...users, ...invitedUsers]); + const invitedUsers = invitations.map((user: V1Beta1User) => ({ + ...user, + invited: true + })); + // @ts-ignore + setUsers([...users, ...invitedUsers]); + } catch (err) { + console.error(err); + } finally { + setIsUsersLoading(false); + } }, [client, organization?.id]); useEffect(() => { @@ -53,7 +61,13 @@ export default function WorkspaceMembers() { - + {organization?.id ? ( + + ) : null} @@ -72,20 +86,32 @@ const ManageMembers = () => ( ); -const MembersTable = ({ users, organizationId }: MembersTableType) => { +const MembersTable = ({ + users, + organizationId, + isLoading +}: MembersTableType) => { let navigate = useNavigate({ from: '/members' }); const tableStyle = users?.length ? { width: '100%' } : { width: '100%', height: '100%' }; + const columns = useMemo( + () => getColumns(organizationId, isLoading), + [organizationId, isLoading] + ); + + const data = useMemo( + () => + isLoading ? [{ id: 1 }, { id: 2 }, { id: 3 }] : users.length ? users : [], + [isLoading, users] + ); return ( ColumnDef[] = organizationId => [ + id: string, + isLoading?: boolean +) => ColumnDef[] = (organizationId, isLoading) => [ { header: '', accessorKey: 'profile_picture', @@ -17,56 +19,75 @@ export const getColumns: ( meta: { style: { width: '30px', + maxHeight: isLoading ? '16px' : 'auto', padding: 0 } }, - cell: ({ row, getValue }) => { - return ( - - ); - } + cell: isLoading + ? () => + : ({ row, getValue }) => { + return ( + + ); + } }, { accessorKey: 'title', meta: { style: { - paddingLeft: 0 + paddingLeft: 0, + maxHeight: isLoading ? '16px' : 'auto' } }, - cell: ({ row, getValue }) => { - return ( - - - {row.original.email} - - ); - } + cell: isLoading + ? () => + : ({ row, getValue }) => { + return ( + + + {row.original.email} + + ); + } }, { accessorKey: 'email', - cell: ({ row, getValue }) => { - // @ts-ignore - return {getValue() || row.original?.user_id}; - } + meta: { + style: { + maxHeight: isLoading ? '16px' : 'auto' + } + }, + cell: isLoading + ? () => + : ({ row, getValue }) => { + return ( + // @ts-ignore + {getValue() || row.original?.user_id} + ); + } }, { header: '', accessorKey: 'id', meta: { style: { - textAlign: 'end' + textAlign: 'end', + maxHeight: isLoading ? '16px' : 'auto' } }, - cell: ({ row }) => ( - - ) + cell: isLoading + ? () => + : ({ row }) => ( + + ) } ]; diff --git a/sdks/js/packages/core/react/components/organization/members/member.types.tsx b/sdks/js/packages/core/react/components/organization/members/member.types.tsx index 010263afe..027e87aea 100644 --- a/sdks/js/packages/core/react/components/organization/members/member.types.tsx +++ b/sdks/js/packages/core/react/components/organization/members/member.types.tsx @@ -10,5 +10,6 @@ export enum MemberActionmethods { export type MembersTableType = { users: User[]; - organizationId?: string; + organizationId: string; + isLoading?: boolean; }; From 4f95d7606bcf35d55106fe0ae4dd0789e8b4cd96 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Fri, 8 Sep 2023 12:50:24 +0530 Subject: [PATCH 06/11] feat: add user loading in context --- .../general/general.workspace.tsx | 2 +- .../components/organization/members/index.tsx | 8 +-- .../components/organization/user/avatar.tsx | 25 ++++--- .../components/organization/user/update.tsx | 71 +++++++++++-------- .../core/react/contexts/FrontierContext.tsx | 16 ++++- 5 files changed, 73 insertions(+), 49 deletions(-) diff --git a/sdks/js/packages/core/react/components/organization/general/general.workspace.tsx b/sdks/js/packages/core/react/components/organization/general/general.workspace.tsx index 5dba186d2..afdc32b12 100644 --- a/sdks/js/packages/core/react/components/organization/general/general.workspace.tsx +++ b/sdks/js/packages/core/react/components/organization/general/general.workspace.tsx @@ -116,7 +116,7 @@ export const GeneralOrganization = ({ variant="primary" type="submit" style={{ width: 'fit-content' }} - disabled={isLoading} + disabled={isLoading || isSubmitting} > {isSubmitting ? 'updating...' : 'Update'} diff --git a/sdks/js/packages/core/react/components/organization/members/index.tsx b/sdks/js/packages/core/react/components/organization/members/index.tsx index be3feda63..7eee11b0f 100644 --- a/sdks/js/packages/core/react/components/organization/members/index.tsx +++ b/sdks/js/packages/core/react/components/organization/members/index.tsx @@ -62,11 +62,8 @@ export default function WorkspaceMembers() { {organization?.id ? ( - + // TODO: fix table loading styling + ) : null} @@ -110,6 +107,7 @@ const MembersTable = ({ return ( { - const { user } = useFrontier(); + const { user, isUserLoading: isLoading } = useFrontier(); return ( - - + {isLoading ? ( + + ) : ( + + )} + + {/* Pick a profile picture for your avatar. Max size: 5 Mb - + */} ); }; diff --git a/sdks/js/packages/core/react/components/organization/user/update.tsx b/sdks/js/packages/core/react/components/organization/user/update.tsx index a0c1e8216..638ebd071 100644 --- a/sdks/js/packages/core/react/components/organization/user/update.tsx +++ b/sdks/js/packages/core/react/components/organization/user/update.tsx @@ -9,6 +9,7 @@ import { } from '@raystack/apsara'; import { useEffect } from 'react'; import { Controller, useForm } from 'react-hook-form'; +import Skeleton from 'react-loading-skeleton'; import { toast } from 'sonner'; import * as yup from 'yup'; import { useFrontier } from '~/react/contexts/FrontierContext'; @@ -21,7 +22,7 @@ const generalSchema = yup .required(); export const UpdateProfile = () => { - const { client, user } = useFrontier(); + const { client, user, isUserLoading: isLoading } = useFrontier(); const { reset, control, @@ -55,20 +56,23 @@ export const UpdateProfile = () => { - ( - - )} - defaultValue={user?.title} - control={control} - name="title" - /> - + {isLoading ? ( + + ) : ( + ( + + )} + defaultValue={user?.title} + control={control} + name="title" + /> + )} {errors.title && String(errors.title?.message)} @@ -76,22 +80,26 @@ export const UpdateProfile = () => { - ( - - )} - defaultValue={user?.name} - control={control} - name="email" - /> + {isLoading ? ( + + ) : ( + ( + + )} + defaultValue={user?.name} + control={control} + name="email" + /> + )} {errors.title && String(errors.title?.message)} @@ -103,6 +111,7 @@ export const UpdateProfile = () => { variant="primary" type="submit" style={{ width: 'fit-content' }} + disabled={isLoading || isSubmitting} > {isSubmitting ? 'updating...' : 'Update'} diff --git a/sdks/js/packages/core/react/contexts/FrontierContext.tsx b/sdks/js/packages/core/react/contexts/FrontierContext.tsx index e544f5c84..4de8f0fb1 100644 --- a/sdks/js/packages/core/react/contexts/FrontierContext.tsx +++ b/sdks/js/packages/core/react/contexts/FrontierContext.tsx @@ -43,6 +43,9 @@ interface FrontierContextProviderProps { isActiveOrganizationLoading: boolean; setIsActiveOrganizationLoading: Dispatch>; + + isUserLoading: boolean; + setIsUserLoading: Dispatch>; } const defaultConfig = { @@ -72,6 +75,9 @@ const initialValues: FrontierContextProviderProps = { activeOrganization: undefined, setActiveOrganization: () => undefined, + isUserLoading: false, + setIsUserLoading: () => undefined, + isActiveOrganizationLoading: false, setIsActiveOrganizationLoading: () => undefined }; @@ -96,6 +102,7 @@ export const FrontierContextProvider = ({ useState(); const [isActiveOrganizationLoading, setIsActiveOrganizationLoading] = useState(false); + const [isUserLoading, setIsUserLoading] = useState(false); useEffect(() => { async function getFrontierInformation() { @@ -116,6 +123,7 @@ export const FrontierContextProvider = ({ useEffect(() => { async function getFrontierCurrentUser() { try { + setIsUserLoading(true); const { data: { user } } = await frontierClient.frontierServiceGetCurrentUser(); @@ -124,10 +132,12 @@ export const FrontierContextProvider = ({ console.error( 'frontier:sdk:: There is problem with fetching current user information' ); + } finally { + setIsUserLoading(false); } } getFrontierCurrentUser(); - }, []); + }, [frontierClient]); useEffect(() => { async function getFrontierCurrentUserGroups() { @@ -183,7 +193,9 @@ export const FrontierContextProvider = ({ activeOrganization, setActiveOrganization, isActiveOrganizationLoading, - setIsActiveOrganizationLoading + setIsActiveOrganizationLoading, + isUserLoading, + setIsUserLoading }} > {children} From d14c1859043cc760a829c0806256bab9f80f0a12 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Mon, 11 Sep 2023 12:25:23 +0530 Subject: [PATCH 07/11] feat: add loading screen to teams table --- .../components/organization/members/index.tsx | 26 +++++++---- .../components/organization/teams/index.tsx | 41 ++++++++++++----- .../organization/teams/teams.columns.tsx | 45 +++++++++++-------- 3 files changed, 76 insertions(+), 36 deletions(-) diff --git a/sdks/js/packages/core/react/components/organization/members/index.tsx b/sdks/js/packages/core/react/components/organization/members/index.tsx index 7eee11b0f..ed580bcf9 100644 --- a/sdks/js/packages/core/react/components/organization/members/index.tsx +++ b/sdks/js/packages/core/react/components/organization/members/index.tsx @@ -53,6 +53,16 @@ export default function WorkspaceMembers() { fetchOrganizationUser(); }, [fetchOrganizationUser, routerState.location.key]); + const updatedUsers = useMemo( + () => + isUsersLoading + ? [{ id: 1 }, { id: 2 }, { id: 3 }] + : users.length + ? users + : [], + [isUsersLoading, users] + ); + return ( @@ -62,8 +72,12 @@ export default function WorkspaceMembers() { {organization?.id ? ( - // TODO: fix table loading styling - + ) : null} @@ -99,16 +113,12 @@ const MembersTable = ({ [organizationId, isLoading] ); - const data = useMemo( - () => - isLoading ? [{ id: 1 }, { id: 2 }, { id: 3 }] : users.length ? users : [], - [isLoading, users] - ); return ( { - const { - // @ts-ignore - data: { groups = [] } - } = await client?.adminServiceListGroups({ orgId: organization?.id }); - setTeams(groups); + try { + setIsTeamsLoading(true); + const { + // @ts-ignore + data: { groups = [] } + } = await client?.adminServiceListGroups({ orgId: organization?.id }); + setTeams(groups); + } catch (err) { + console.error(err); + } finally { + setIsTeamsLoading(false); + } }, [client, organization?.id]); useEffect(() => { @@ -34,6 +42,16 @@ export default function WorkspaceTeams() { getTeams(); }, [client, getTeams, organization?.id]); + const updatedTeams = useMemo( + () => + isTeamsLoading + ? [{ id: 1 }, { id: 2 }, { id: 3 }] + : teams.length + ? teams + : [], + [isTeamsLoading, teams] + ); + return ( @@ -41,7 +59,8 @@ export default function WorkspaceTeams() { - + {/* @ts-ignore */} + @@ -49,13 +68,15 @@ export default function WorkspaceTeams() { ); } -const TeamsTable = ({ teams }: WorkspaceTeamProps) => { +const TeamsTable = ({ teams, isLoading }: WorkspaceTeamProps) => { let navigate = useNavigate({ from: '/members' }); const tableStyle = teams?.length ? { width: '100%' } : { width: '100%', height: '100%' }; + const columns = useMemo(() => getColumns(isLoading), [isLoading]); + return ( [] = [ +export const getColumns: ( + isLoading?: boolean +) => ColumnDef[] = isLoading => [ { header: 'Title', accessorKey: 'name', - cell: ({ row, getValue }) => ( - - {getValue()} - - ) + cell: isLoading + ? () => + : ({ row, getValue }) => ( + + {getValue()} + + ) }, { accessorKey: 'members', - cell: ({ row, getValue }) => ( - - ) + cell: isLoading + ? () => + : ({ row, getValue }) => ( + + ) }, { header: '', @@ -40,9 +47,11 @@ export const columns: ColumnDef[] = [ textAlign: 'end' } }, - cell: ({ row, getValue }) => ( - - ) + cell: isLoading + ? () => + : ({ row, getValue }) => ( + + ) } ]; From 57887d64f09881b68efe9a7ee540b2b0933c0060 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Mon, 11 Sep 2023 12:38:16 +0530 Subject: [PATCH 08/11] feat: add loading screen to projects table --- .../components/organization/project/index.tsx | 41 +++++++++++---- .../organization/project/projects.columns.tsx | 52 ++++++++++++------- 2 files changed, 65 insertions(+), 28 deletions(-) diff --git a/sdks/js/packages/core/react/components/organization/project/index.tsx b/sdks/js/packages/core/react/components/organization/project/index.tsx index 16bc7f471..f977ce582 100644 --- a/sdks/js/packages/core/react/components/organization/project/index.tsx +++ b/sdks/js/packages/core/react/components/organization/project/index.tsx @@ -2,23 +2,31 @@ import { Button, DataTable, EmptyState, Flex, Text } from '@raystack/apsara'; import { Outlet, useNavigate, useRouterState } from '@tanstack/react-router'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { useFrontier } from '~/react/contexts/FrontierContext'; import { V1Beta1Project } from '~/src'; import { styles } from '../styles'; -import { columns } from './projects.columns'; +import { getColumns } from './projects.columns'; export default function WorkspaceProjects() { const { client, activeOrganization: organization } = useFrontier(); const routerState = useRouterState(); const [projects, setProjects] = useState([]); + const [isProjectsLoading, setIsProjectsLoading] = useState(false); const getProjects = useCallback(async () => { - const { - // @ts-ignore - data: { projects = [] } - } = await client?.adminServiceListProjects({ orgId: organization?.id }); - setProjects(projects); + try { + setIsProjectsLoading(true); + const { + // @ts-ignore + data: { projects = [] } + } = await client?.adminServiceListProjects({ orgId: organization?.id }); + setProjects(projects); + } catch (err) { + console.error(err); + } finally { + setIsProjectsLoading(false); + } }, [client, organization?.id]); useEffect(() => { @@ -29,6 +37,15 @@ export default function WorkspaceProjects() { getProjects(); }, [client, getProjects, organization?.id]); + const updatedProjects = useMemo( + () => + isProjectsLoading + ? [{ id: 1 }, { id: 2 }, { id: 3 }] + : projects.length + ? projects + : [], + [isProjectsLoading, projects] + ); return ( @@ -36,7 +53,11 @@ export default function WorkspaceProjects() { - + @@ -46,15 +67,17 @@ export default function WorkspaceProjects() { interface WorkspaceProjectsProps { projects: V1Beta1Project[]; + isLoading?: boolean; } -const ProjectsTable = ({ projects }: WorkspaceProjectsProps) => { +const ProjectsTable = ({ projects, isLoading }: WorkspaceProjectsProps) => { let navigate = useNavigate({ from: '/projects' }); const tableStyle = projects?.length ? { width: '100%' } : { width: '100%', height: '100%' }; + const columns = useMemo(() => getColumns(isLoading), [isLoading]); return ( [] = [ +export const getColumns: ( + isLoading?: boolean +) => ColumnDef[] = isLoading => [ { accessorKey: 'name', - cell: ({ row, getValue }) => { - return ( - - {getValue()} - - ); - } + cell: isLoading + ? () => + : ({ row, getValue }) => { + return ( + + {getValue()} + + ); + } }, { accessorKey: 'privacy', - cell: info => {info.getValue() ?? 'Public'} + cell: isLoading + ? () => + : info => {info.getValue() ?? 'Public'} }, { accessorKey: 'members', - cell: ({ row, getValue }) => + cell: isLoading + ? () => + : ({ row, getValue }) => }, { header: '', @@ -43,9 +55,11 @@ export const columns: ColumnDef[] = [ textAlign: 'end' } }, - cell: ({ row, getValue }) => ( - - ) + cell: isLoading + ? () => + : ({ row, getValue }) => ( + + ) } ]; From 977a0248a96ec6f0e20322f5670036035eef8623 Mon Sep 17 00:00:00 2001 From: Rishabh Date: Mon, 11 Sep 2023 12:38:31 +0530 Subject: [PATCH 09/11] chore: remove custom style from member table loader --- .../organization/members/member.columns.tsx | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/sdks/js/packages/core/react/components/organization/members/member.columns.tsx b/sdks/js/packages/core/react/components/organization/members/member.columns.tsx index 15f8c2ad4..bc1597e9a 100644 --- a/sdks/js/packages/core/react/components/organization/members/member.columns.tsx +++ b/sdks/js/packages/core/react/components/organization/members/member.columns.tsx @@ -19,7 +19,6 @@ export const getColumns: ( meta: { style: { width: '30px', - maxHeight: isLoading ? '16px' : 'auto', padding: 0 } }, @@ -40,8 +39,7 @@ export const getColumns: ( accessorKey: 'title', meta: { style: { - paddingLeft: 0, - maxHeight: isLoading ? '16px' : 'auto' + paddingLeft: 0 } }, cell: isLoading @@ -57,11 +55,7 @@ export const getColumns: ( }, { accessorKey: 'email', - meta: { - style: { - maxHeight: isLoading ? '16px' : 'auto' - } - }, + meta: {}, cell: isLoading ? () => : ({ row, getValue }) => { @@ -76,8 +70,7 @@ export const getColumns: ( accessorKey: 'id', meta: { style: { - textAlign: 'end', - maxHeight: isLoading ? '16px' : 'auto' + textAlign: 'end' } }, cell: isLoading From 264826db10e6f54e92e79c057619e8645c31f15b Mon Sep 17 00:00:00 2001 From: Rishabh Date: Mon, 11 Sep 2023 12:44:24 +0530 Subject: [PATCH 10/11] feat: add loading screen to domains table --- .../organization/domain/domain.columns.tsx | 33 ++++++++----- .../components/organization/domain/index.tsx | 48 +++++++++++++++---- 2 files changed, 59 insertions(+), 22 deletions(-) diff --git a/sdks/js/packages/core/react/components/organization/domain/domain.columns.tsx b/sdks/js/packages/core/react/components/organization/domain/domain.columns.tsx index dc4f63791..baaa66de4 100644 --- a/sdks/js/packages/core/react/components/organization/domain/domain.columns.tsx +++ b/sdks/js/packages/core/react/components/organization/domain/domain.columns.tsx @@ -5,8 +5,11 @@ import { useNavigate } from '@tanstack/react-router'; import { toast } from 'sonner'; import { useFrontier } from '~/react/contexts/FrontierContext'; import { V1Beta1Domain } from '~/src'; +import Skeleton from 'react-loading-skeleton'; -export const columns: ColumnDef[] = [ +export const getColumns: ( + isLoading?: boolean +) => ColumnDef[] = isLoading => [ { accessorKey: 'name', meta: { @@ -14,17 +17,21 @@ export const columns: ColumnDef[] = [ paddingLeft: 0 } }, - cell: ({ row, getValue }) => { - return ( - - {row.original.name} - - ); - } + cell: isLoading + ? () => + : ({ row, getValue }) => { + return ( + + {row.original.name} + + ); + } }, { accessorKey: 'created_at', - cell: info => {info.getValue()} + cell: isLoading + ? () => + : info => {info.getValue()} }, { header: '', @@ -34,9 +41,11 @@ export const columns: ColumnDef[] = [ textAlign: 'end' } }, - cell: ({ row, getValue }) => ( - - ) + cell: isLoading + ? () => + : ({ row, getValue }) => ( + + ) } ]; diff --git a/sdks/js/packages/core/react/components/organization/domain/index.tsx b/sdks/js/packages/core/react/components/organization/domain/index.tsx index 80077a401..c2edea493 100644 --- a/sdks/js/packages/core/react/components/organization/domain/index.tsx +++ b/sdks/js/packages/core/react/components/organization/domain/index.tsx @@ -2,24 +2,34 @@ import { Button, DataTable, EmptyState, Flex, Text } from '@raystack/apsara'; import { Outlet, useNavigate, useRouterState } from '@tanstack/react-router'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; import { useFrontier } from '~/react/contexts/FrontierContext'; import { V1Beta1Domain } from '~/src'; import { styles } from '../styles'; -import { columns } from './domain.columns'; +import { getColumns } from './domain.columns'; export default function Domain() { const { client, activeOrganization: organization } = useFrontier(); const routerState = useRouterState(); const [domains, setDomains] = useState([]); + const [isDomainsLoading, setIsDomainsLoading] = useState(false); const getDomains = useCallback(async () => { - if (!organization?.id) return; - const { - // @ts-ignore - data: { domains = [] } - } = await client?.frontierServiceListOrganizationDomains(organization?.id); - setDomains(domains); + try { + setIsDomainsLoading(true); + if (!organization?.id) return; + const { + // @ts-ignore + data: { domains = [] } + } = await client?.frontierServiceListOrganizationDomains( + organization?.id + ); + setDomains(domains); + } catch (err) { + console.error(err); + } finally { + setIsDomainsLoading(false); + } }, [client, organization?.id]); useEffect(() => { @@ -30,6 +40,16 @@ export default function Domain() { getDomains(); }, [client, getDomains, organization?.id]); + const updatedDomains = useMemo( + () => + isDomainsLoading + ? [{ id: 1 }, { id: 2 }, { id: 3 }] + : domains.length + ? domains + : [], + [isDomainsLoading, domains] + ); + return ( @@ -38,7 +58,8 @@ export default function Domain() { - + {/* @ts-ignore */} + @@ -61,13 +82,20 @@ const AllowedEmailDomains = () => { ); }; -const Domains = ({ domains }: { domains: V1Beta1Domain[] }) => { +const Domains = ({ + domains, + isLoading +}: { + domains: V1Beta1Domain[]; + isLoading?: boolean; +}) => { let navigate = useNavigate({ from: '/domains' }); const tableStyle = domains?.length ? { width: '100%' } : { width: '100%', height: '100%' }; + const columns = useMemo(() => getColumns(isLoading), [isLoading]); return ( Date: Mon, 11 Sep 2023 12:45:34 +0530 Subject: [PATCH 11/11] chore: bump package.json version --- sdks/js/packages/core/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdks/js/packages/core/package.json b/sdks/js/packages/core/package.json index 04a8be972..63290632a 100644 --- a/sdks/js/packages/core/package.json +++ b/sdks/js/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@raystack/frontier", - "version": "0.0.5", + "version": "0.0.6", "description": "A js library for frontier", "sideEffects": false, "main": "./dist/index.js", @@ -97,4 +97,4 @@ "publishConfig": { "access": "public" } -} +} \ No newline at end of file