way nicer flow and almost ready for fetching and displaying but stay patient
This commit is contained in:
@@ -84,8 +84,15 @@ export default function Links() {
|
|||||||
</span>
|
</span>
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
|
|
||||||
<Tooltip title={"code blocks: coming soon"}>
|
<Tooltip
|
||||||
<button className="bg-gray-300 bg-opacity-25 p-2 rounded hover:bg-opacity-40 ml-2">
|
title={
|
||||||
|
"code blocks: copy the link and paste it in here when you are done"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
onClick={() => window.open("https://www.codepile.net/", "_blank")}
|
||||||
|
className="bg-gray-300 bg-opacity-25 p-2 rounded hover:bg-opacity-40 ml-2"
|
||||||
|
>
|
||||||
<FaCode className="text-lg text-white" />
|
<FaCode className="text-lg text-white" />
|
||||||
</button>
|
</button>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|||||||
@@ -193,7 +193,6 @@ export default function DashboardRoom() {
|
|||||||
{teamRooms.length}
|
{teamRooms.length}
|
||||||
</span>
|
</span>
|
||||||
</Radio.Button>
|
</Radio.Button>
|
||||||
|
|
||||||
<Radio.Button value={RoomTypeFilter.live}>
|
<Radio.Button value={RoomTypeFilter.live}>
|
||||||
{RoomTypeFilter.live}{" "}
|
{RoomTypeFilter.live}{" "}
|
||||||
<span className="text-xs text-orange-500">
|
<span className="text-xs text-orange-500">
|
||||||
|
|||||||
@@ -2,13 +2,14 @@ import { FaArchive, FaExternalLinkAlt, FaFilePdf } from "react-icons/fa";
|
|||||||
import Link from "../models/link";
|
import Link from "../models/link";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
import { BsThreeDots } from "react-icons/bs";
|
import { BsThreeDots } from "react-icons/bs";
|
||||||
|
import LinkIcon from "./LinkIcon";
|
||||||
|
|
||||||
export default function LinkCard(props: { link?: Link }) {
|
export default function LinkCard(props: { link?: Link }) {
|
||||||
return (
|
return (
|
||||||
<span className="flex flex-col rounded-lg">
|
<span className="flex flex-col rounded-lg">
|
||||||
{/* attmnt header */}
|
{/* attmnt header */}
|
||||||
<span className="flex flex-row bg-gray-300 bg-opacity-25 py-5 px-3 items-center justify-start">
|
<span className="flex flex-row bg-gray-300 bg-opacity-25 py-5 px-3 items-center justify-start">
|
||||||
<RenderFileIcon className="text-4xl text-orange-300 mr-2" />
|
<LinkIcon className="text-4xl text-orange-300 mr-2" />
|
||||||
|
|
||||||
<span className="flex flex-col items-baseline mr-10 space-y-1">
|
<span className="flex flex-col items-baseline mr-10 space-y-1">
|
||||||
<span className="text-md font-bold text-white">report.pdf</span>
|
<span className="text-md font-bold text-white">report.pdf</span>
|
||||||
@@ -57,7 +58,3 @@ export default function LinkCard(props: { link?: Link }) {
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function RenderFileIcon(props) {
|
|
||||||
return <FaFilePdf {...props} />;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import {
|
||||||
|
FaAtlassian,
|
||||||
|
FaFileAlt,
|
||||||
|
FaFileCode,
|
||||||
|
FaFileImage,
|
||||||
|
FaFilePdf,
|
||||||
|
FaGithubSquare,
|
||||||
|
FaGoogleDrive,
|
||||||
|
} from "react-icons/fa";
|
||||||
|
import Link, { LinkType } from "../models/link";
|
||||||
|
|
||||||
|
export default function LinkIcon(props: {
|
||||||
|
className?: string;
|
||||||
|
linkType: LinkType;
|
||||||
|
}) {
|
||||||
|
// github
|
||||||
|
|
||||||
|
// atlassian
|
||||||
|
|
||||||
|
// drive
|
||||||
|
|
||||||
|
// onedrive
|
||||||
|
|
||||||
|
// dropbox
|
||||||
|
|
||||||
|
// image
|
||||||
|
|
||||||
|
// pdf
|
||||||
|
|
||||||
|
// https://www.codepile.net/ for code snippets
|
||||||
|
|
||||||
|
const { className, linkType, ...rest } = props;
|
||||||
|
|
||||||
|
switch (linkType) {
|
||||||
|
case LinkType.default:
|
||||||
|
return <FaFileAlt {...rest} className={`${className} text-slate-300 `} />;
|
||||||
|
case LinkType.atlassian:
|
||||||
|
return <FaAtlassian {...rest} className={`${className} text-sky-500 `} />;
|
||||||
|
case LinkType.codePile:
|
||||||
|
return <FaFileCode {...rest} className={`${className} text-blue-500 `} />;
|
||||||
|
case LinkType.github:
|
||||||
|
return (
|
||||||
|
<FaGithubSquare {...rest} className={`${className} text-gray-500 `} />
|
||||||
|
);
|
||||||
|
case LinkType.googleDrive:
|
||||||
|
return (
|
||||||
|
<FaGoogleDrive {...rest} className={`${className} text-emerald-500 `} />
|
||||||
|
);
|
||||||
|
case LinkType.image:
|
||||||
|
return (
|
||||||
|
<FaFileImage {...rest} className={`${className} text-purple-500 `} />
|
||||||
|
);
|
||||||
|
case LinkType.pdf:
|
||||||
|
<FaFilePdf {...rest} className={`${className} text-orange-500 `} />;
|
||||||
|
default:
|
||||||
|
return (
|
||||||
|
<FaFileAlt {...rest} className={`${className} text-orange-500 `} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,40 +1,202 @@
|
|||||||
|
import { Divider, Select, Switch, Tooltip } from "antd";
|
||||||
|
const { Option } = Select;
|
||||||
|
|
||||||
import Modal from "antd/lib/modal/Modal";
|
import Modal from "antd/lib/modal/Modal";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
import toast from "react-hot-toast";
|
||||||
|
import { useAuth } from "../../contexts/authContext";
|
||||||
import {
|
import {
|
||||||
ShowModalType,
|
ShowModalType,
|
||||||
useKeyboardContext,
|
useKeyboardContext,
|
||||||
} from "../../contexts/keyboardContext";
|
} from "../../contexts/keyboardContext";
|
||||||
|
import { useTeamDashboardContext } from "../../contexts/teamDashboardContext";
|
||||||
|
import Link, { LinkType } from "../../models/link";
|
||||||
|
import LinkIcon from "../LinkIcon";
|
||||||
|
|
||||||
export default function CreateOrUpdateLink() {
|
export default function CreateOrUpdateLink() {
|
||||||
|
const { currUser } = useAuth();
|
||||||
const { handleModalType, showModalType } = useKeyboardContext();
|
const { handleModalType, showModalType } = useKeyboardContext();
|
||||||
|
const { teamUsers, team } = useTeamDashboardContext();
|
||||||
|
|
||||||
function closeModal() {
|
function closeModal() {
|
||||||
handleModalType(ShowModalType.na);
|
handleModalType(ShowModalType.na);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSelectRecipients(value) {
|
||||||
|
// passed in array of selections...userIds
|
||||||
|
|
||||||
|
setRecipientsSelected(value);
|
||||||
|
|
||||||
|
console.log(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSelectRecipientMode(isChecked) {
|
||||||
|
// clear the list of recipients if team selected
|
||||||
|
if (isChecked) {
|
||||||
|
setRecipientsSelected([]);
|
||||||
|
setIsTeamLink(true);
|
||||||
|
} else {
|
||||||
|
setRecipientsSelected([]);
|
||||||
|
setIsTeamLink(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleSubmitLink() {
|
||||||
|
if (!link || !name) {
|
||||||
|
toast.error("Please add a valid link and name");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// if it's a team link, make sure recipients is null ... but the model should handle this for us?
|
||||||
|
|
||||||
|
try {
|
||||||
|
const newLink = new Link(
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
link,
|
||||||
|
team.id,
|
||||||
|
recipientsSelected,
|
||||||
|
currUser.uid
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(newLink);
|
||||||
|
|
||||||
|
// send to database
|
||||||
|
} catch (error) {
|
||||||
|
toast.error("Something went wrong in sending the link.");
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const [link, setLink] = useState<string>("");
|
const [link, setLink] = useState<string>("");
|
||||||
|
const [name, setName] = useState<string>("");
|
||||||
|
const [description, setDescription] = useState<string>("");
|
||||||
|
const [showMoreDetails, setShowMoreDetails] = useState<boolean>(false);
|
||||||
|
const [isTeamLink, setIsTeamLink] = useState<boolean>(true);
|
||||||
|
const [recipientsSelected, setRecipientsSelected] = useState<string[]>([]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title="Link Details"
|
title="Link Details"
|
||||||
visible={showModalType == ShowModalType.createLink}
|
visible={showModalType == ShowModalType.createLink}
|
||||||
onCancel={closeModal}
|
onCancel={closeModal}
|
||||||
onOk={closeModal}
|
onOk={handleSubmitLink}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col space-y-5">
|
||||||
<span className="flex flex-col items-start">
|
<span className="flex flex-col items-start">
|
||||||
<span className="text-lg">Link</span>
|
<span className="text-lg">Link</span>
|
||||||
<span className="text-gray-300 text-xs mb-2">
|
<span className="text-gray-300 text-xs mb-2">
|
||||||
Please make sure this is valid for others to access.
|
Please make sure this is valid for others to access.
|
||||||
</span>
|
</span>
|
||||||
|
{/* icon and link input */}
|
||||||
|
<span className="flex flex-row items-center space-x-2 w-full">
|
||||||
|
<LinkIcon className="text-3xl" linkType={Link.getLinkType(link)} />
|
||||||
|
|
||||||
|
<input
|
||||||
|
autoFocus
|
||||||
|
className="flex-1 rounded-lg bg-gray-50 p-3"
|
||||||
|
value={link}
|
||||||
|
placeholder="https://jira.atlassian.com/team/xxx"
|
||||||
|
onChange={(e) => setLink(e.target.value)}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span className="flex flex-col items-start">
|
||||||
|
<span className="text-lg">Name</span>
|
||||||
|
<span className="text-gray-300 text-xs mb-2">
|
||||||
|
Make sure this makes sense to who you are sending it to.
|
||||||
|
</span>
|
||||||
|
|
||||||
<input
|
<input
|
||||||
className="w-full rounded-lg bg-gray-50 p-3"
|
className="w-full rounded-lg bg-gray-50 p-3"
|
||||||
value={link}
|
value={name}
|
||||||
placeholder="https://drive.google.com/xxx"
|
placeholder="ex. User Story - Customer Creating Orders"
|
||||||
onChange={(e) => setLink(e.target.value)}
|
onChange={(e) => setName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
<span className="flex flex-col items-start">
|
||||||
|
<span className="text-lg">Recipients</span>
|
||||||
|
<span className="text-gray-300 text-xs mb-2">
|
||||||
|
Choose team or individual recipients
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span className="mb-2">
|
||||||
|
<Switch
|
||||||
|
defaultChecked
|
||||||
|
onChange={handleSelectRecipientMode}
|
||||||
|
checkedChildren={<span>Team</span>}
|
||||||
|
unCheckedChildren={<span>Members</span>}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
{/* select team members to send to */}
|
||||||
|
{!isTeamLink ? (
|
||||||
|
<Select
|
||||||
|
mode="multiple"
|
||||||
|
allowClear
|
||||||
|
style={{ width: "100%" }}
|
||||||
|
placeholder="Please select team members"
|
||||||
|
onChange={handleSelectRecipients}
|
||||||
|
value={recipientsSelected}
|
||||||
|
optionLabelProp="label"
|
||||||
|
filterOption={(input, option) =>
|
||||||
|
option.props.label.toLowerCase().indexOf(input.toLowerCase()) >=
|
||||||
|
0
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{teamUsers.map((tu) => {
|
||||||
|
return (
|
||||||
|
<Option key={tu.id} label={tu.firstName}>
|
||||||
|
{tu.firstName} {tu.lastName}
|
||||||
|
</Option>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</Select>
|
||||||
|
) : (
|
||||||
|
<></>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<Tooltip
|
||||||
|
title={"Private mode coming soon, but keep it collaborative for now."}
|
||||||
|
className="flex flex-col"
|
||||||
|
></Tooltip>
|
||||||
|
|
||||||
|
{showMoreDetails ? (
|
||||||
|
<>
|
||||||
|
<Divider />
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="text-sm text-gray-300 text-left underline decoration-gray-300"
|
||||||
|
onClick={() => setShowMoreDetails(false)}
|
||||||
|
>
|
||||||
|
Hide details...
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<span className="flex flex-col items-start">
|
||||||
|
<span className="text-md">Description</span>
|
||||||
|
<span className="text-gray-300 text-xs mb-2">
|
||||||
|
Optional - Add any pointers about this file.
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<textarea
|
||||||
|
className="w-full rounded-lg bg-gray-50 p-3"
|
||||||
|
value={description}
|
||||||
|
placeholder="ex. Please review this and add feedback asap"
|
||||||
|
onChange={(e) => setDescription(e.target.value)}
|
||||||
|
/>
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<button
|
||||||
|
className="text-sm text-gray-300 text-left underline decoration-gray-300"
|
||||||
|
onClick={() => setShowMoreDetails(true)}
|
||||||
|
>
|
||||||
|
Click to show more details...
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -190,6 +190,7 @@ export default function CreateOrUpdateRoomModal(props: IModalProps) {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
<input
|
<input
|
||||||
|
autoFocus
|
||||||
className="w-full rounded-lg bg-gray-50 p-3"
|
className="w-full rounded-lg bg-gray-50 p-3"
|
||||||
value={roomLink}
|
value={roomLink}
|
||||||
placeholder="https://meet.google.com/xxx-xxxx"
|
placeholder="https://meet.google.com/xxx-xxxx"
|
||||||
|
|||||||
+65
-8
@@ -6,25 +6,82 @@ export default class Link {
|
|||||||
description: string;
|
description: string;
|
||||||
link: string; //url for file
|
link: string; //url for file
|
||||||
|
|
||||||
state: AttachmentState = AttachmentState.active;
|
state: LinkState = LinkState.active;
|
||||||
|
type: LinkType;
|
||||||
isLoomScreenshare: boolean = false;
|
|
||||||
|
|
||||||
teamId: string;
|
teamId: string;
|
||||||
// if it's not a teamAttachment, then have a list of members who it's for
|
// if it's not a teamAttachment, then have a list of members who it's for
|
||||||
|
private _recipients: string[]; // userIds
|
||||||
|
|
||||||
createdByUserId: string;
|
createdByUserId: string;
|
||||||
createdDate: Timestamp;
|
createdDate: Timestamp;
|
||||||
|
|
||||||
constructor(id: string, name: string, description: string) {}
|
constructor(
|
||||||
|
_name: string,
|
||||||
|
_description: string,
|
||||||
|
_link: string,
|
||||||
|
_teamId: string,
|
||||||
|
recipientsArr: string[],
|
||||||
|
_createdByUserId: string
|
||||||
|
) {
|
||||||
|
this.name = _name;
|
||||||
|
this.description = _description;
|
||||||
|
this.link = _link;
|
||||||
|
this.teamId = _teamId;
|
||||||
|
this.recipients = recipientsArr;
|
||||||
|
this.createdByUserId = _createdByUserId;
|
||||||
|
|
||||||
|
this.type = Link.getLinkType(_link);
|
||||||
|
}
|
||||||
|
|
||||||
|
public get recipients(): string[] {
|
||||||
|
return this._recipients;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set recipients(arrUserIds: string[]) {
|
||||||
|
if (!this._recipients || this._recipients?.length == 0) {
|
||||||
|
this._recipients = null;
|
||||||
|
} else {
|
||||||
|
this._recipients = arrUserIds;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static getLinkType(url: string): LinkType {
|
||||||
|
if (url.includes(LinkType.github)) {
|
||||||
|
return LinkType.github;
|
||||||
|
} else if (url.includes(LinkType.atlassian)) {
|
||||||
|
return LinkType.atlassian;
|
||||||
|
} else if (url.includes(LinkType.googleDrive)) {
|
||||||
|
return LinkType.googleDrive;
|
||||||
|
} else if (
|
||||||
|
url.includes(".png") ||
|
||||||
|
url.includes(".jpg") ||
|
||||||
|
url.includes(".svg") ||
|
||||||
|
url.includes(".gif")
|
||||||
|
) {
|
||||||
|
return LinkType.image;
|
||||||
|
} else if (url.includes(LinkType.pdf)) {
|
||||||
|
return LinkType.pdf;
|
||||||
|
} else if (url.includes(LinkType.codePile)) {
|
||||||
|
return LinkType.codePile;
|
||||||
|
} else {
|
||||||
|
return LinkType.default;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AttachmentState {
|
export enum LinkState {
|
||||||
active = "active",
|
active = "active",
|
||||||
archived = "archived",
|
archived = "archived",
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AttachmentType {
|
export enum LinkType {
|
||||||
link = "link",
|
default = "default",
|
||||||
screenshare = "",
|
github = "github",
|
||||||
|
atlassian = "atlassian",
|
||||||
|
googleDrive = "drive.google",
|
||||||
|
onedrive = "onedrive",
|
||||||
|
image = "image",
|
||||||
|
pdf = "pdf",
|
||||||
|
codePile = "codepile",
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"folders": [
|
||||||
|
{
|
||||||
|
"path": "."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "..\\nirvana-web"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"settings": {}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user