Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions src/app/drive/components/ShareDialog/ShareDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import { useShareItemActions } from './hooks/useShareItemActions';
import { useShareItemInvitations } from './hooks/useShareItemInvitations';
import { useShareItemUserRoles } from './hooks/useShareItemUserRoles';
import AccessRequests from './components/AccessRequests';

export type ShareDialogProps = {
user: UserSettings;
Expand Down Expand Up @@ -164,7 +165,6 @@
if (!itemToShare?.item) return;

actionDispatch(setIsLoading(true));
// Change object type of itemToShare to AdvancedSharedItem
let shareAccessMode: AccessMode = 'public';

const itemType = itemToShare?.item.isFolder ? 'folder' : 'file';
Expand Down Expand Up @@ -234,6 +234,8 @@
}
};

const onOpenPendingAccess = () => actionDispatch(setView('requests'));

Check warning on line 237 in src/app/drive/components/ShareDialog/ShareDialog.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this useless assignment to variable "onOpenPendingAccess".

See more on https://sonarcloud.io/project/issues?id=internxt_drive-web&issues=AZ5PiWAvLY4tfplsIQtB&open=AZ5PiWAvLY4tfplsIQtB&pullRequest=1966

const onOpenStopSharingDialog = useCallback(() => {
actionDispatch(setShowStopSharingConfirmation(true));
}, [actionDispatch]);
Expand All @@ -243,7 +245,7 @@
}, [actionDispatch]);

const View = (viewProps: ViewProps): JSX.Element => {
const view = {
const view: Record<ViewProps['view'], JSX.Element> = {
general: (
<>
<div className="relative flex flex-col">
Expand All @@ -265,6 +267,20 @@
)}
</div>
</div>
{/* Pending access requests from users */}
{/* <button
className="flex bg-gray-5 flex-row w-full justify-between items-center rounded-lg p-3 mt-1.5"
onClick={onOpenPendingAccess}
>
<p className="font-medium text-gray-100">{translate('modals.shareModal.requests.title')}</p>
<div className="flex flex-row gap-1 items-center">
<div className="flex px-2 py-1 bg-primary rounded-full h-max">
TODO: Add the real notification count

Check warning on line 278 in src/app/drive/components/ShareDialog/ShareDialog.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this "TODO" comment.

See more on https://sonarcloud.io/project/issues?id=internxt_drive-web&issues=AZ5PiWAvLY4tfplsIQtC&open=AZ5PiWAvLY4tfplsIQtC&pullRequest=1966
<p className="text-xs font-medium">2</p>
</div>
<CaretRight size={24} />
</div>
</button> */}

{/* List of users invited to the shared item */}
<InvitedUsersList
Expand Down Expand Up @@ -344,6 +360,7 @@
/>
</>
),
requests: <AccessRequests />,
invite: (
<ShareInviteDialog
onClose={() => {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Tray } from '@phosphor-icons/react';
import { useTranslationContext } from 'app/i18n/provider/TranslationProvider';

const AccessRequestsEmptyState = () => {
const { translate } = useTranslationContext();
return (
<div className="flex flex-col items-center justify-center h-full">
<Tray size={64} className="text-primary" />
<p className="text-lg font-medium text-gray-100">{translate('modals.shareModal.requests.empty')}</p>
</div>
);
};

export default AccessRequestsEmptyState;
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import AccessRequestsEmptyState from './empty';
import AccessRequestsList from './list';

const AccessRequests = () => {
const mockedRequests = [
{
user: {
name: 'John Doe',
email: '4V0oX@example.com',
avatar: 'https://i.pravatar.cc/150?u=a042581f4e29026024d',
},
message: 'Hello there',
onDecline: () => {},
onAccept: () => {},
},
];

if (mockedRequests.length === 0) {
return (
<div className="flex flex-1 flex-col justify-center">
<AccessRequestsEmptyState />
</div>
);
}

return (
<div className="flex min-h-[430px] flex-col items-center w-full">
<AccessRequestsList accessRequestList={mockedRequests} />
</div>
);
};

export default AccessRequests;
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { Avatar, Button } from '@internxt/ui';
import { useTranslationContext } from 'app/i18n/provider/TranslationProvider';

interface AccessRequestItem {
user: {
name: string;
email: string;
avatar: string;
};
message?: string;
onDecline: () => void;
onAccept: () => void;
}

const RequestCheap = ({ user, message, onDecline, onAccept }: AccessRequestItem) => {
const { translate } = useTranslationContext();
return (
<div className="flex flex-col gap-3.5 border-b border-gray-10 pb-3.5 last:border-b-0 last:pb-0">
<div className="flex flex-row justify-between">
{/* User info */}
<div className="flex flex-row">
<Avatar diameter={32} fullName={user.name} src={user.avatar} />
<div className="flex flex-col">
<p className="font-medium text-gray-100">{user.name}</p>
<p className="text-sm text-gray-50">{user.email}</p>
</div>
</div>

<div className="flex flex-row gap-2">
<Button variant="secondary" onClick={onDecline}>
{translate('modals.shareModal.requests.actions.deny')}
</Button>
{/* TODO: Add a dropdown to select the user role */}

Check warning on line 33 in src/app/drive/components/ShareDialog/components/AccessRequests/list/index.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Complete the task associated to this "TODO" comment.

See more on https://sonarcloud.io/project/issues?id=internxt_drive-web&issues=AZ5PiV80LY4tfplsIQs_&open=AZ5PiV80LY4tfplsIQs_&pullRequest=1966
<Button variant="primary" onClick={onAccept}>
{translate('modals.shareModal.requests.actions.accept')}
</Button>
</div>
</div>

<div className="flex bg-gray-5 p-4 rounded-lg">
<p>{message}</p>
</div>
</div>
);
};

const AccessRequestsList = ({ accessRequestList }: { accessRequestList: AccessRequestItem[] }) => {
return (
<div className="flex flex-col w-full">
{accessRequestList.map((request, index) => (
<RequestCheap key={index} {...request} />

Check warning on line 51 in src/app/drive/components/ShareDialog/components/AccessRequests/list/index.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Do not use Array index in keys

See more on https://sonarcloud.io/project/issues?id=internxt_drive-web&issues=AZ5PiV81LY4tfplsIQtA&open=AZ5PiV81LY4tfplsIQtA&pullRequest=1966
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have some sonar cloud warnings

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. The design/components are added but not used (so we do not break the current flow for now). This way, we just need to add the logic and this design later and that's it.

They will be fixed later when completing the task.

))}
</div>
);
};

export default AccessRequestsList;
146 changes: 74 additions & 72 deletions src/app/drive/views/RequestAccess/RequestAccess.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,26 @@
import { useSelector } from 'react-redux';
import { RootState } from 'app/store';
import { UserSettings } from '@internxt/sdk/dist/shared/types/userSettings';
import { LockSimple, CheckCircle } from '@phosphor-icons/react';
import { LockSimple, CheckCircle, Clock } from '@phosphor-icons/react';
import { useTranslationContext } from 'app/i18n/provider/TranslationProvider';
import { Button } from '@internxt/ui';
import InternxtLogo from 'assets/icons/big-logo.svg?react';
import './RequestAccess.scss';
import { logOut } from 'services/auth.service';
import UserCheapCard from './UserCheapCard';

const TEXTAREA_MAX_LENGTH = 950;
const TEXTAREA_MAX_LENGTH = 1000;
type Views = 'requestAccess' | 'requestSent' | 'waitingApproval';

function RequestAccess(): JSX.Element {
const user = useSelector<RootState, UserSettings | undefined>((state) => state.user.user);
const urlParams = new URLSearchParams(window.location.search);
const isRequestingAccess = urlParams.get('requestAccess');
const folderuuid = urlParams.get('folderuuid');

const { translate } = useTranslationContext();

const [view, setView] = useState<Views>('requestAccess');
const [messageText, setMessageText] = useState<string>('');

Check warning on line 23 in src/app/drive/views/RequestAccess/RequestAccess.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this useless assignment to variable "setMessageText".

See more on https://sonarcloud.io/project/issues?id=internxt_drive-web&issues=AZ5PiWBHLY4tfplsIQtD&open=AZ5PiWBHLY4tfplsIQtD&pullRequest=1966
const [messageTextLimit, setMessageTextLimit] = useState<boolean>(false);

Check warning on line 24 in src/app/drive/views/RequestAccess/RequestAccess.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this useless assignment to variable "messageTextLimit".

See more on https://sonarcloud.io/project/issues?id=internxt_drive-web&issues=AZ5PiWBHLY4tfplsIQtE&open=AZ5PiWBHLY4tfplsIQtE&pullRequest=1966
const [requestSent, setRequestSent] = useState<boolean>(false);

useEffect(() => {
if (messageText.length >= TEXTAREA_MAX_LENGTH) {
Expand All @@ -31,86 +31,88 @@
}
}, [messageText]);

const onRequestAcces = (): void => {
const onRequestAccess = (): void => {

Check warning on line 34 in src/app/drive/views/RequestAccess/RequestAccess.tsx

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Remove this useless assignment to variable "onRequestAccess".

See more on https://sonarcloud.io/project/issues?id=internxt_drive-web&issues=AZ5PiWBHLY4tfplsIQtF&open=AZ5PiWBHLY4tfplsIQtF&pullRequest=1966
// TODO add logic to request access
setRequestSent(true);
setView('requestSent');
};

const onChangeAccount = (): void => {
const queryParams: Record<string, string> = folderuuid ? { folderuuid } : {};
logOut(queryParams);
};

const views: Record<Views, JSX.Element> = {
requestAccess: (
<div className="flex flex-col items-center py-3 gap-4">
<div className="flex flex-col py-3 gap-1 items-center justify-center">
<LockSimple size={64} weight="thin" className="text-primary" />
<h4 className="text-center text-xl font-medium">{translate('modals.shareModal.requestAccess.title')}</h4>
<p className="font-regular text-center text-base text-gray-60">
{translate('modals.shareModal.requestAccess.description')}
</p>
</div>

{/* <div className="flex w-full flex-col">
<textarea
value={messageText}
placeholder={translate('modals.shareModal.requestAccess.textarea')}
rows={4}
className=" w-full max-w-lg resize-none rounded-md border border-gray-40 bg-gray-1 p-3 pl-4 outline-none ring-primary/10 focus:border-primary focus:ring-3"
onChange={(e) => setMessageText(String(e.target.value))}
maxLength={1000}
/>
<span
className={`font-regular mt-2 flex w-full justify-end text-xs text-gray-50 ${
messageTextLimit && 'text-red'
}`}
>
{messageText.length === 0 ? 0 : messageText.length}/1000
</span>
</div>
<Button variant="primary" className="cursor-pointer" onClick={onRequestAccess}>
{translate('modals.shareModal.requestAccess.requestButton')}
</Button> */}
</div>
),
requestSent: (
<div className="flex flex-col gap-4 items-center justify-center">
<CheckCircle size={80} weight="fill" className="text-primary" />
<div className="flex flex-col gap-3 items-center text-center">
<h4 className="text-center text-xl font-medium">
{translate('modals.shareModal.requestAccess.requestSent.title')}
</h4>
<p className="font-regular mb-3 text-center text-base text-gray-60">
{translate('modals.shareModal.requestAccess.requestSent.description')}
</p>
</div>
</div>
),
waitingApproval: (
<div className="flex flex-col gap-4 items-center justify-center px-10">
<Clock size={64} className="text-primary" />
<div className="flex flex-col gap-2 items-center text-center">
<h4 className="text-center text-xl font-medium">
{translate('modals.shareModal.requestAccess.waitingForApproval.title')}
</h4>
<p className="font-regular text-center text-base text-gray-60">
{translate('modals.shareModal.requestAccess.waitingForApproval.description')}
</p>
</div>
</div>
),
};

return (
<div className="flex h-full w-full flex-col items-center overflow-auto bg-white sm:bg-gray-5">
<div className="flex h-full w-full flex-col items-center overflow-auto bg-surface sm:bg-gray-5">
<div className="flex shrink-0 flex-row justify-center self-stretch py-10 sm:justify-start sm:pl-20">
<InternxtLogo className="h-auto w-28 text-gray-100" />
</div>

<div className="flex h-full w-full max-w-xs shrink-0 flex-col items-center justify-start pb-8">
{!requestSent ? (
<>
<div className="flex w-full flex-col items-center rounded-2xl bg-white p-5 text-gray-100 transition-all duration-100 ease-out sm:shadow-subtle-hard">
<LockSimple size={80} weight="thin" className="mt-3" />
<h4 className="mt-4 text-center text-xl font-medium">
{translate('modals.shareModal.requestAccess.title')}
</h4>
<p className="font-regular mb-3 mt-1 text-center text-base text-gray-60">
{translate('modals.shareModal.requestAccess.description')}
</p>
{isRequestingAccess && (
<>
<textarea
value={messageText}
placeholder={translate('modals.shareModal.requestAccess.textarea')}
rows={4}
className="mt-5 w-full max-w-lg resize-none rounded-md border border-gray-40 bg-gray-1 p-3 pl-4 outline-none ring-primary/10 focus:border-primary focus:ring-3"
onChange={(e) => setMessageText(String(e.target.value))}
maxLength={1000}
/>
<span
className={`font-regular mt-2 flex w-full justify-end text-xs text-gray-50 ${
messageTextLimit && 'text-red'
}`}
>
{messageText.length === 0 ? 0 : messageText.length}/1000
</span>
<Button variant="primary" className="mt-2 w-full cursor-pointer" onClick={onRequestAcces}>
{translate('modals.shareModal.requestAccess.requestButton')}
</Button>
</>
)}
</div>

<div className="request-access-user-container mt-4 w-full rounded-2xl bg-white p-5 text-gray-100 transition-all duration-100 ease-out sm:shadow-subtle-hard">
<div className="flex w-full items-center justify-between">
<div className="mr-4 flex-1">
<p className="text-sm font-medium">{translate('modals.shareModal.requestAccess.logged')}</p>
<p
className="font-regular mt-0.5 flex-1 truncate text-base text-gray-50"
style={{ maxWidth: '167px' }}
title={user?.email}
>
{user?.email}
</p>
</div>
<Button variant="secondary" className="cursor-pointer" onClick={onChangeAccount}>
{translate('modals.shareModal.requestAccess.change')}
</Button>
</div>
</div>
</>
) : (
<div className="flex w-full max-w-xs flex-col items-center rounded-2xl bg-white p-5 text-gray-100 shadow-subtle-hard transition-all duration-100 ease-out">
<CheckCircle size={80} weight="thin" className="mt-3 text-primary" />
<h4 className="mt-4 text-center text-xl font-medium">
{translate('modals.shareModal.requestAccess.requestSent')}
</h4>
<p className="font-regular mb-3 mt-1 text-center text-base text-gray-60">
{translate('modals.shareModal.requestAccess.confirmation')}
</p>
</div>
)}
<div className="flex w-full max-w-[414px] shrink-0 flex-col items-center justify-start pb-8">
<div className="flex w-full h-[431px] flex-col items-center justify-center rounded-2xl bg-surface p-5 text-gray-100 transition-all duration-100 ease-out sm:shadow-subtle-hard">
{views[view]}
</div>
<UserCheapCard user={user} onChangeAccount={onChangeAccount} />
</div>
</div>
);
Expand Down
34 changes: 34 additions & 0 deletions src/app/drive/views/RequestAccess/UserCheapCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { UserSettings } from '@internxt/sdk/dist/shared/types/userSettings';
import { useTranslationContext } from 'app/i18n/provider/TranslationProvider';
import { Button } from '@internxt/ui';

interface RequestAccessUserCardProps {
user: UserSettings | undefined;
onChangeAccount: () => void;
}

const UserCheapCard = ({ user, onChangeAccount }: Readonly<RequestAccessUserCardProps>): JSX.Element => {
const { translate } = useTranslationContext();

return (
<div className="request-access-user-container mt-4 w-full rounded-2xl bg-surface p-5 text-gray-100 transition-all duration-100 ease-out sm:shadow-subtle-hard">
<div className="flex w-full items-center justify-between">
<div className="mr-4 flex-1">
<p className="text-sm font-medium">{translate('modals.shareModal.requestAccess.logged')}</p>
<p
className="font-regular mt-0.5 flex-1 truncate text-base text-gray-50"
style={{ maxWidth: '167px' }}
title={user?.email}
>
{user?.email}
</p>
</div>
<Button variant="secondary" className="cursor-pointer" onClick={onChangeAccount}>
{translate('modals.shareModal.requestAccess.change')}
</Button>
</div>
</div>
);
};

export default UserCheapCard;
Loading
Loading