Skip to content

Commit

Permalink
Merge pull request #161 from wizelineacademy/development
Browse files Browse the repository at this point in the history
Development
  • Loading branch information
william-monroy authored Nov 29, 2023
2 parents cd1ea2d + 85ea477 commit b804bb1
Show file tree
Hide file tree
Showing 38 changed files with 820 additions and 122 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/playwright.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Playwright Tests
on:
push:
branches: [ main, master ]
pull_request:
branches: [ main, master ]
jobs:
test:
timeout-minutes: 60
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 18
- name: Install dependencies
run: npm install -g pnpm && pnpm install
- name: Install Playwright Browsers
run: pnpm exec playwright install --with-deps
- name: Run Playwright tests
run: pnpm exec playwright test
- uses: actions/upload-artifact@v3
if: always()
with:
name: playwright-report
path: playwright-report/
retention-days: 30
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,7 @@ yarn-error.log*

# vercel
.vercel
/test-results/
/playwright-report/
/blob-report/
/playwright/.cache/
2 changes: 1 addition & 1 deletion apps/web/app/(root)/admin/group/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import GroupBody from "@/components/admin/groupBody/organisms/group-body";

export default function GroupPage(): JSX.Element {
export default function GroupPage(): JSX.Element {
return (
<div>
<GroupBody />
Expand Down
4 changes: 2 additions & 2 deletions apps/web/app/(root)/admin/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export default async function AdminRootLayout({children}: {children: React.React
redirect("/api/auth/login");
}

const allUsersGroupId = 1
const initialGroups: Group[] = sortGroups((await getAllGroups()).data || [], allUsersGroupId)
const allWizelinersGroupId = 1
const initialGroups: Group[] = sortGroups((await getAllGroups()).data || [], allWizelinersGroupId)

return (
<PrismaUserContextProvider initialPrismaUser={prismaUser}>
Expand Down
3 changes: 2 additions & 1 deletion apps/web/app/api/ai/openai/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ export async function POST(
return new StreamingTextResponse(stream, { status: 200 });
} catch (error: any) {
// If an error occurs, log it to the console and send a message to the user
// console.error(error);
console.log(error.message)
console.error(error);
return new NextResponse(`Error: ${error.message}`, { status: 500 });
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
import { Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader } from "@nextui-org/react";
import { useEffect, useState } from "react";
import { useContext, useEffect, useState } from "react";
import type { Group } from "@prisma/client";
import { toast } from "sonner";
import { AiFillDelete } from "react-icons/ai"
import { groupsAreEqual, isValidGroup } from "@/helpers/group-helpers";
import { GroupsActionType, groupsAreEqual, isValidGroup } from "@/helpers/group-helpers";
import ConfirmDeleteModal from "@/components/shared/molecules/confirm-delete-modal";
import { GroupsContext, type GroupsContextShape } from "@/context/groups-context";
import NewGroupMenu from "./edit-group-menu";

interface EditGroupMenuModalProps {
isNew: boolean;
allowElimination: boolean;
initialGroup: Group;
isOpen: boolean;
onGroupSave: (savedGroup: Group) => void;
onGroupDeletion?: (deletedGroup: Group) => void;
onModalClose: () => void;
}

export default function EditGroupMenuModal({isNew, initialGroup, isOpen, onGroupSave, onGroupDeletion, onModalClose}: EditGroupMenuModalProps): JSX.Element {
export default function EditGroupMenuModal({isNew, allowElimination, initialGroup, isOpen, onGroupSave, onGroupDeletion, onModalClose}: EditGroupMenuModalProps): JSX.Element {
const [group, setGroup] = useState<Group>(initialGroup)
const [isLoading, setIsLoading] = useState<boolean>(false)
const [confirmDeleteModalIsOpen, setConfirmDeleteModalIsOpen] = useState<boolean>(false)
const modalHorizontalPadding = 5
const saveIsDisabled = !isValidGroup(group) || groupsAreEqual(initialGroup, group)
const groupsContext = useContext<GroupsContextShape | null>(GroupsContext)

useEffect(() => {
if (!isOpen){
Expand All @@ -41,7 +44,7 @@ export default function EditGroupMenuModal({isNew, initialGroup, isOpen, onGroup
}

const handleDeleteButtonPress: (e: any) => void = (_) => {
if (onGroupDeletion && !isNew){
if (onGroupDeletion && !isNew && allowElimination){
onModalClose()
setConfirmDeleteModalIsOpen(true)
}
Expand Down Expand Up @@ -115,6 +118,9 @@ export default function EditGroupMenuModal({isNew, initialGroup, isOpen, onGroup
if (!response.ok){
throw new Error("Network response was not ok")
}
groupsContext?.groupsDispatch({
type: GroupsActionType.Delete,
})
return response.json()
})
.then((deletedGroup) => {
Expand Down Expand Up @@ -142,7 +148,7 @@ export default function EditGroupMenuModal({isNew, initialGroup, isOpen, onGroup
<div className="flex flex-row justify-between items-center w-full">
<p>{isNew ? "New group" : "Edit group"}</p>

{!isNew ?
{!isNew && allowElimination ?
<Button color="danger" isIconOnly onPress={handleDeleteButtonPress}>
<AiFillDelete/>
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface GroupHeaderProps {
export function GroupHeader({
groupData,
onGroupsSettingsPress,
setUpdatedUsers
setUpdatedUsers,
}: GroupHeaderProps): JSX.Element {
const [creditsModalIsOpen, setCreditsModalIsOpen] = useState<boolean>(false)
const [descriptionModalIsOpen, setDescriptionModalIsOpen] = useState<boolean>(false)
Expand All @@ -44,12 +44,13 @@ export function GroupHeader({
}

return (
<div className="flex flex-wrap items-start justify-between my-2 sm:ml-10 mt-0 pt-0">
<div className="flex flex-wrap items-start justify-between mb-2 mt-2 pt-0">
{/* Adjust the order of items for XS screens */}
<div className="w-full sm:w-1/2 order-2 sm:order-1 text-start">
<div className="w-full sm:w-1/2 order-2 sm:order-1 text-start sm:mt-10">
<button className="flex flex-row justify-center items-center gap-3" onClick={handleGroupNameClick} type="button">

<h3 className="text-3xl font-bold">{groupData.name}</h3>
<LuInfo size="0.8rem"/>
<LuInfo size="1rem"/>
</button>

{/* Placeholder for credits information below the group name */}
Expand Down
63 changes: 36 additions & 27 deletions apps/web/components/admin/groupBody/molecules/group-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ interface GroupTableProps {
setUpdatedUsers: any;
idGroup: number;
users: User[];
allowMembersEditing: boolean;
}

//columns
Expand Down Expand Up @@ -70,6 +71,7 @@ export default function GroupTable({
setUpdatedUsers,
users,
idGroup,
allowMembersEditing
}: GroupTableProps): JSX.Element {
const { isOpen, onOpen, onOpenChange } = useDisclosure();

Expand Down Expand Up @@ -158,7 +160,8 @@ export default function GroupTable({

if (hasSearchFilter) {
filteredUsers = filteredUsers.filter((user) =>
user.name.toLowerCase().includes(filterValue.toLowerCase())
user.name.toLowerCase().includes(filterValue.toLowerCase()) ||
user.email.toLowerCase().includes(filterValue.toLowerCase())
);
}
if (
Expand Down Expand Up @@ -321,6 +324,29 @@ export default function GroupTable({
}, []);

const topContent = useMemo(() => {
const membersEditingButton: JSX.Element = selectedKeys instanceof Set && selectedKeys.size > 0 ? (
<Button
color="danger"
endContent={<FaMinus />}
onClick={() => {
void removeUsersFromGroup();
}}
size="sm"
>
Remove Users
</Button>
) : (
<Button
className="text-white"
color="success"
endContent={<AiOutlinePlus />}
onClick={onOpen}
size="sm"
>
Add Users
</Button>
)

return (
<div className="flex flex-col gap-4">
<div className="flex justify-between gap-3 items-center">
Expand All @@ -331,7 +357,7 @@ export default function GroupTable({
onClear();
}}
onValueChange={onSearchChange}
placeholder="Search by name..."
placeholder="Search by name or email..."
size="sm"
startContent={<AiOutlineSearch />}
value={filterValue}
Expand Down Expand Up @@ -387,28 +413,11 @@ export default function GroupTable({
))}
</DropdownMenu>
</Dropdown>
{selectedKeys instanceof Set && selectedKeys.size > 0 ? (
<Button
color="danger"
endContent={<FaMinus />}
onClick={() => {
void removeUsersFromGroup();
}}
size="sm"
>
Remove Users
</Button>
) : (
<Button
className="text-white"
color="success"
endContent={<AiOutlinePlus />}
onClick={onOpen}
size="sm"
>
Add Users
</Button>
)}

{/*If the editing of the group's members is possible, show corresponding button*/}
{allowMembersEditing ?
membersEditingButton
: null}
</div>
</div>
<div className="flex justify-between items-center">
Expand Down Expand Up @@ -494,13 +503,13 @@ export default function GroupTable({
},
}}
classNames={{
wrapper: "max-h-[382px] shadow-none p-4",
wrapper: "shadow-none p-4 overflow-y-scroll h-[calc(100vh-20rem)]",
}}
isHeaderSticky
onSelectionChange={setSelectedKeys as any}
onSortChange={setSortDescriptor as any}
selectedKeys={selectedKeys}
selectionMode="multiple"
selectionMode={allowMembersEditing ? "multiple" : "single"}
sortDescriptor={sortDescriptor}
topContent={topContent}
topContentPlacement="outside"
Expand All @@ -516,7 +525,7 @@ export default function GroupTable({
</TableColumn>
)}
</TableHeader>
<TableBody emptyContent="No users found" items={sortedItems}>
<TableBody className="h-full" emptyContent="No users found" items={sortedItems}>
{(item) => (
<TableRow key={item.id}>
{(columnKey) => (
Expand Down
16 changes: 10 additions & 6 deletions apps/web/components/admin/groupBody/organisms/group-body.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
"use client";
// Import necessary hooks and utilities from React and Next.js
import { useContext, useEffect, useState } from "react";
import { useParams } from "next/navigation";
import { useParams , useRouter } from "next/navigation";
import type { Group } from "@prisma/client";
import { Spinner } from "@nextui-org/react";
import { toast } from "sonner";
Expand All @@ -20,13 +20,14 @@ export default function GroupBody(): JSX.Element {
const sidebarGroupsContext = useContext<GroupsContextShape | null>(
GroupsContext
);
const [editGroupModalIsOpen, setEditGroupModalIsOpen] =
useState<boolean>(false);
const [editGroupModalIsOpen, setEditGroupModalIsOpen] = useState<boolean>(false);
const router = useRouter();
const params = useParams();
const idGroup = Number(params.id);
const allowGroupEditing: boolean = idGroup !== 1 // 1: the id of the 'All Wizeliners' group.

// State for storing group data
const [groupData, setGroupData] = useState<GroupData | null>(null);
const [groupData, setGroupData] = useState<GroupData | null>(placeHolderGroupData());

// State for tracking loading status
const [loading, setLoading] = useState<boolean>(true);
Expand Down Expand Up @@ -80,9 +81,10 @@ export default function GroupBody(): JSX.Element {
setGroupData(data);
console.log(data);
} catch (err: any) {
router.push("/admin/group/1") // Redirect to 'All Wizeliners' if group's data can't be fetched.
// setError(err.message);
console.log(err);
toast.error("Failed getting group data");
toast.error(`Failed in fetching the data of group ${idGroup}.`);
} finally {
setLoading(false);
}
Expand All @@ -106,7 +108,7 @@ export default function GroupBody(): JSX.Element {
// if (error) return <div>Error: {error}</div>;

return (
<div className="p-5 h-full">
<div className="p-5 h-full mt-0 pt-3">
{/* Group Header */}
<GroupHeader
groupData={groupData ?? placeHolderGroupData()}
Expand All @@ -115,12 +117,14 @@ export default function GroupBody(): JSX.Element {
/>
{/* Group Table */}
<GroupTable
allowMembersEditing={allowGroupEditing}
idGroup={idGroup}
setUpdatedUsers={setUpdatedUsers}
users={groupData?.users ?? []}
/>

<EditGroupMenuModal
allowElimination={allowGroupEditing}
initialGroup={{ ...groupData, users: undefined } as Group}
isNew={false}
isOpen={editGroupModalIsOpen}
Expand Down
8 changes: 6 additions & 2 deletions apps/web/components/admin/groupSidebar/atoms/group-card.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { Card, CardBody, Tooltip } from "@nextui-org/react";
import type { Group } from "@prisma/client";
import { MdOutlineGroup, MdOutlineGroups } from "react-icons/md"

interface GroupCardProps {
isAllUsersGroup: boolean;
group: Group;
isSelected: boolean;
onPress: () => void;
}

export default function GroupCard({
isAllUsersGroup,
group,
isSelected,
onPress,
Expand All @@ -34,13 +37,14 @@ export default function GroupCard({
<button className="w-full" onClick={handleCardPress} type="button">
<Tooltip content={cardTooltipContent} delay={1000} placement="right">
<Card
className={`flex flex-row items-center h-11 py-2 pl-2 pr-0 border-none rounded-md shadow-none hover:bg-white hover:bg-opacity-20 ${cardBackgroundColor}`}
className={`flex flex-row items-center h-11 py-2 pl-2 pr-0 border-none rounded-md shadow-none hover:bg-white hover:bg-opacity-20 ${cardBackgroundColor}`}
fullWidth
radius="none"
shadow="none"
>
<CardBody>
<div className="flex flex-row justify-start items-center w-full overflow-scroll scrollbar-hide">
<div className="flex flex-row justify-start items-center gap-2 w-full overflow-scroll scrollbar-hide">
{isAllUsersGroup ? <MdOutlineGroups color="white"/> : <MdOutlineGroup color="white"/> }
<p className="text-xs text-white whitespace-nowrap">{group.name}</p>
</div>
</CardBody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@ export default function GroupList({groups, selectedGroup, onGroupPress}: GroupLi
<div className="flex flex-col space-y-2 w-full scrollbar-hide">
{groups.map((group, index) => (
<>
<GroupCard group={group} isSelected={selectedGroup === group.id} key={group.id} onPress={() => {onGroupPress(group.id)}}/>
<GroupCard
group={group}
isAllUsersGroup={index === 0}
isSelected={selectedGroup === group.id}
key={group.id} onPress={() => {onGroupPress(group.id)}}
/>

{index === 0 ?
<Divider className="m-1 my-0 dark"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ export default function GroupSidebar(): JSX.Element {
<div
className={`${
sidebarIsVisible ? "hidden" : "block"
} w-2 absolute -right-6 z-50 top-5 md:top-2`}
} w-2 absolute -right-6 z-50 top-2 md:top-2`}
>
{!sidebarIsVisible ? sidebarVisibilityButton : null}
</div>
Expand Down
Loading

0 comments on commit b804bb1

Please sign in to comment.