From 531e70beda92f65c5e285ba4167badb67bc11cd5 Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Tue, 14 Nov 2023 11:44:13 -0300 Subject: [PATCH 1/7] change: GroupContent tab subfolders --- .../{ => GroupContentMaterials}/GroupContentMaterials.less | 0 .../{ => GroupContentMaterials}/GroupContentMaterials.tsx | 0 .../GroupContents/{ => GroupContents}/GroupContents.less | 0 .../GroupContents/{ => GroupContents}/GroupContents.tsx | 0 src/pages/Group/GroupTabs/GroupContents/index.ts | 2 ++ src/pages/Group/GroupTabs/index.ts | 3 +-- 6 files changed, 3 insertions(+), 2 deletions(-) rename src/pages/Group/GroupTabs/GroupContents/{ => GroupContentMaterials}/GroupContentMaterials.less (100%) rename src/pages/Group/GroupTabs/GroupContents/{ => GroupContentMaterials}/GroupContentMaterials.tsx (100%) rename src/pages/Group/GroupTabs/GroupContents/{ => GroupContents}/GroupContents.less (100%) rename src/pages/Group/GroupTabs/GroupContents/{ => GroupContents}/GroupContents.tsx (100%) create mode 100644 src/pages/Group/GroupTabs/GroupContents/index.ts diff --git a/src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials.less b/src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials/GroupContentMaterials.less similarity index 100% rename from src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials.less rename to src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials/GroupContentMaterials.less diff --git a/src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials.tsx b/src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials/GroupContentMaterials.tsx similarity index 100% rename from src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials.tsx rename to src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials/GroupContentMaterials.tsx diff --git a/src/pages/Group/GroupTabs/GroupContents/GroupContents.less b/src/pages/Group/GroupTabs/GroupContents/GroupContents/GroupContents.less similarity index 100% rename from src/pages/Group/GroupTabs/GroupContents/GroupContents.less rename to src/pages/Group/GroupTabs/GroupContents/GroupContents/GroupContents.less diff --git a/src/pages/Group/GroupTabs/GroupContents/GroupContents.tsx b/src/pages/Group/GroupTabs/GroupContents/GroupContents/GroupContents.tsx similarity index 100% rename from src/pages/Group/GroupTabs/GroupContents/GroupContents.tsx rename to src/pages/Group/GroupTabs/GroupContents/GroupContents/GroupContents.tsx diff --git a/src/pages/Group/GroupTabs/GroupContents/index.ts b/src/pages/Group/GroupTabs/GroupContents/index.ts new file mode 100644 index 00000000..1aba1118 --- /dev/null +++ b/src/pages/Group/GroupTabs/GroupContents/index.ts @@ -0,0 +1,2 @@ +export * from "./GroupContents/GroupContents" +export * from "./GroupContentMaterials/GroupContentMaterials" diff --git a/src/pages/Group/GroupTabs/index.ts b/src/pages/Group/GroupTabs/index.ts index 6b359d3c..f5133b2b 100644 --- a/src/pages/Group/GroupTabs/index.ts +++ b/src/pages/Group/GroupTabs/index.ts @@ -1,6 +1,5 @@ export * from "./GroupTabs"; -export * from "./GroupContents/GroupContents"; -export * from "./GroupContents/GroupContentMaterials"; +export * from "./GroupContents"; export * from "./GroupPeople/GroupPeople"; export * from "./GroupGroups/GroupGroups"; From 6ab809996fbc1ef4e35a155b25beaa505f54e6e1 Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Tue, 14 Nov 2023 13:30:50 -0300 Subject: [PATCH 2/7] change: refresh data can accept content id to set --- .../ProfileInfo/ProfileBio/ProfileBio.tsx | 2 -- src/pages/Group/Group.tsx | 14 ++++++++++++-- src/pages/Group/GroupContext.tsx | 15 ++++++++++++++- .../GroupContentMaterials.tsx | 12 ++++-------- 4 files changed, 30 insertions(+), 13 deletions(-) diff --git a/src/components/ProfileInfo/ProfileBio/ProfileBio.tsx b/src/components/ProfileInfo/ProfileBio/ProfileBio.tsx index 37658d75..7607ea51 100644 --- a/src/components/ProfileInfo/ProfileBio/ProfileBio.tsx +++ b/src/components/ProfileInfo/ProfileBio/ProfileBio.tsx @@ -26,8 +26,6 @@ export function ProfileBio(props: ProfileBioProps) { ? { backgroundImage: `url(${groupBannerUrl(props.organization)})` } : { backgroundColor: "var(--primary-color)" } - console.dir({headerBackground}); - return (
diff --git a/src/pages/Group/Group.tsx b/src/pages/Group/Group.tsx index 4aa9ae25..ac8ab04e 100644 --- a/src/pages/Group/Group.tsx +++ b/src/pages/Group/Group.tsx @@ -1,7 +1,7 @@ import { useContext, useEffect, useState } from "react"; import { Navigate, useLoaderData } from "react-router-dom"; -import { GroupContext, GroupIntro, GroupTabRenderer, GroupTabs, fetchGroupPageData, type AvailableTabs, type GroupContextType, type GroupPageLoaderResponse } from "@/pages/Group"; +import { GroupContext, GroupIntro, GroupTabRenderer, GroupTabs, fetchGroupPageData, type AvailableTabs, type GroupContextType, type GroupPageLoaderResponse, RefreshGroupOptions } from "@/pages/Group"; import { ProfileBio, ProfileGroups } from "@/components/ProfileInfo"; import { AuthContext } from "@/contexts/Auth"; import "./Group.less"; @@ -50,9 +50,14 @@ export function GroupPage() { setCurrentTab(tab); } - async function refreshGroupData() { + async function refreshGroupData(options?: RefreshGroupOptions) { const data = await fetchGroupPageData({ groupPath: page.group?.path }); const newContext = makeContext(data); + + if (options?.currentContentId) { + newContext.currentContent = newContext.folders.find(c => c.id === options.currentContentId); + } + setContext(newContext); return newContext; } @@ -77,6 +82,11 @@ export function GroupPage() { setContext({...this, currentContent: c}); }, + editContent: undefined, + setEditContent(c) { + setContext({...this, editContent: c}); + }, + refreshData: refreshGroupData, }; } diff --git a/src/pages/Group/GroupContext.tsx b/src/pages/Group/GroupContext.tsx index f0928ff5..d9b097ad 100644 --- a/src/pages/Group/GroupContext.tsx +++ b/src/pages/Group/GroupContext.tsx @@ -13,6 +13,15 @@ export type GroupContextType = null | { currentContent: Folder | undefined; setCurrentContent(content: Folder | undefined): any; + /** + * The content being edited/created. + * + * If `null`, should handle creation of a content. If has a value, should handle + * content edit. If `undefined`, no content is being edited nor created. + */ + editContent: Folder | null | undefined; + setEditContent(content: Folder | null | undefined): any; + loggedData: { isParticipant: boolean; profile: Profile; @@ -20,7 +29,11 @@ export type GroupContextType = null | { groups: Group[]; }; - refreshData: () => Promise>; + refreshData: (options?: RefreshGroupOptions) => Promise>; }; +export type RefreshGroupOptions = { + currentContentId?: string; +} + export const GroupContext = createContext(null); diff --git a/src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials/GroupContentMaterials.tsx b/src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials/GroupContentMaterials.tsx index bf42349b..daf7f294 100644 --- a/src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials/GroupContentMaterials.tsx +++ b/src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials/GroupContentMaterials.tsx @@ -296,19 +296,15 @@ export function GroupContentMaterials() { icon: "warning", }).then(res => { if (res.isConfirmed) { - const folderId = groupContext?.currentContent?.id!; + const currentContentId = groupContext?.currentContent?.id!; - UniversimeApi.Capacity.removeContentFromFolder({ folderId, contentIds: material.id }) + UniversimeApi.Capacity.removeContentFromFolder({ folderId: currentContentId, contentIds: material.id }) .then(res => { if (!res.success) return; - groupContext?.refreshData() - .then(data => { - setTimeout(() => { - data.setCurrentContent(data.folders.find(c => c.id === folderId)); - }, 0); - }); + groupContext?.refreshData({currentContentId}) + .then(refreshMaterials); }); } }); From 02e9201db4ccb88965375646d61ddd0e0edf095e Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Tue, 14 Nov 2023 13:36:23 -0300 Subject: [PATCH 3/7] fix: fetch whole page data on remove material from folder --- .../GroupContentMaterials/GroupContentMaterials.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials/GroupContentMaterials.tsx b/src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials/GroupContentMaterials.tsx index daf7f294..31734c0a 100644 --- a/src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials/GroupContentMaterials.tsx +++ b/src/pages/Group/GroupTabs/GroupContents/GroupContentMaterials/GroupContentMaterials.tsx @@ -303,8 +303,7 @@ export function GroupContentMaterials() { if (!res.success) return; - groupContext?.refreshData({currentContentId}) - .then(refreshMaterials); + refreshMaterials(); }); } }); From 17d38da245bf73b75d64efca027cd637646f3f8e Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Tue, 14 Nov 2023 14:27:35 -0300 Subject: [PATCH 4/7] change: add div props to ActionButton --- src/components/ActionButton/ActionButton.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/components/ActionButton/ActionButton.tsx b/src/components/ActionButton/ActionButton.tsx index 001e35cc..968d54bf 100644 --- a/src/components/ActionButton/ActionButton.tsx +++ b/src/components/ActionButton/ActionButton.tsx @@ -1,14 +1,19 @@ +import { HTMLAttributes } from "react" import "./ActionButton.less" export interface ActionButtonProps{ name : string + buttonProps?: HTMLAttributes; } export function ActionButton(props : ActionButtonProps){ + const className = ["action-button-container", props.buttonProps?.className] + .filter(c => !!c && c.length > 0) + .join(" "); return( -
+
{props.name} From 1d83be9d9f94f4b0861a18f499b119fb0420ceef Mon Sep 17 00:00:00 2001 From: Douglas Sebastian Date: Tue, 14 Nov 2023 16:19:41 -0300 Subject: [PATCH 5/7] feat: create and edit content --- .../GroupContents/GroupContents.tsx | 12 +- .../ManageContent/ManageContent.less | 106 +++++++++++ .../ManageContent/ManageContent.tsx | 166 ++++++++++++++++++ .../Group/GroupTabs/GroupContents/index.ts | 1 + src/services/UniversimeApi/Capacity/Folder.ts | 4 + 5 files changed, 286 insertions(+), 3 deletions(-) create mode 100644 src/pages/Group/GroupTabs/GroupContents/ManageContent/ManageContent.less create mode 100644 src/pages/Group/GroupTabs/GroupContents/ManageContent/ManageContent.tsx diff --git a/src/pages/Group/GroupTabs/GroupContents/GroupContents/GroupContents.tsx b/src/pages/Group/GroupTabs/GroupContents/GroupContents/GroupContents.tsx index 290f3a5c..d51a9aa8 100644 --- a/src/pages/Group/GroupTabs/GroupContents/GroupContents/GroupContents.tsx +++ b/src/pages/Group/GroupTabs/GroupContents/GroupContents/GroupContents.tsx @@ -3,7 +3,7 @@ import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; import UniversimeApi from "@/services/UniversimeApi"; import * as SwalUtils from "@/utils/sweetalertUtils"; -import { EMPTY_LIST_CLASS, GroupContentMaterials, GroupContext } from "@/pages/Group"; +import { EMPTY_LIST_CLASS, GroupContentMaterials, GroupContext, ManageContent } from "@/pages/Group"; import { setStateAsValue } from "@/utils/tsxUtils"; import { ProfileImage } from "@/components/ProfileImage/ProfileImage"; import { type OptionInMenu, renderOption, hasAvailableOption } from "@/utils/dropdownMenuUtils" @@ -28,7 +28,9 @@ export function GroupContents() { { text: "Editar", biIcon: "pencil-fill", - disabled() { return true; }, + onSelect(data) { + groupContext.setEditContent(data); + }, hidden() { return groupContext?.group.admin.id !== groupContext?.loggedData.profile.id; }, @@ -49,11 +51,15 @@ export function GroupContents() {
- +
{ makeContentList(groupContext.folders, filterContents) }
+ + ); diff --git a/src/pages/Group/GroupTabs/GroupContents/ManageContent/ManageContent.less b/src/pages/Group/GroupTabs/GroupContents/ManageContent/ManageContent.less new file mode 100644 index 00000000..2cfb54c3 --- /dev/null +++ b/src/pages/Group/GroupTabs/GroupContents/ManageContent/ManageContent.less @@ -0,0 +1,106 @@ +@import url(/src/layouts/colors.less); +@import url(/src/layouts/fonts.less); + +#manage-content { + display: flex; + flex-direction: column; + + background-color: @card-background-color; + border-radius: .625rem; + + padding: 1.5rem; + width: 25vw; + + fieldset { + border: none; + + &:not(:last-child) { + margin-bottom: 1rem; + } + + .field-input { + width: 100%; + margin-top: 5px; + } + + input, textarea { + border: none; + border-radius: .625rem; + + padding: .5em; + + resize: vertical; + + &:focus { + outline: solid 2px @primary-color; + } + } + + .category-select { + border-radius: .625rem; + } + + > legend { + display: flex; + flex-direction: row; + align-items: end; + justify-content: space-between; + + width: 100%; + + font-size: 1.25rem; + font-variant: small-caps; + + .char-counter { + display: inline; + margin-right: .25em; + + font-size: .75em; + } + } + } + + .operation-buttons { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + + > button { + border: none; + + width: 7em; + padding: .75em 0; + border-radius: .625rem; + + color: @font-color-v1; + font-size: .9rem; + text-transform: uppercase; + font-weight: @font-weight-bold; + + cursor: pointer; + + will-change: background-color; + + &.cancel-button { + background-color: @font-color-v6; + &:hover { + background-color: @font-color-v3; + } + } + + &.submit-button { + &:not(:disabled) { + background-color: @primary-color; + &:hover { + background-color: @secondary-color; + } + } + + &:disabled { + background-color: @font-color-v3; + } + } + } + } +} diff --git a/src/pages/Group/GroupTabs/GroupContents/ManageContent/ManageContent.tsx b/src/pages/Group/GroupTabs/GroupContents/ManageContent/ManageContent.tsx new file mode 100644 index 00000000..fdd9ab02 --- /dev/null +++ b/src/pages/Group/GroupTabs/GroupContents/ManageContent/ManageContent.tsx @@ -0,0 +1,166 @@ +import { useContext, useEffect, useState } from "react"; +import Select, { CSSObjectWithLabel, GroupBase, StylesConfig } from 'react-select'; + +import UniversimeApi from "@/services/UniversimeApi"; +import { UniversiModal } from "@/components/UniversiModal"; +import { GroupContext } from "@/pages/Group/GroupContext"; +import { setStateAsValue } from "@/utils/tsxUtils"; + +import type { FolderCreate_ResponseDTO, FolderEdit_ResponseDTO } from "@/services/UniversimeApi/Capacity"; +import type { Category } from "@/types/Capacity"; +import "./ManageContent.less"; + +const MAX_NAME_LENGTH = 50; +const MAX_DESC_LENGTH = 150; + +export function ManageContent() { + const context = useContext(GroupContext); + + const [name, setName] = useState(context?.editContent?.name ?? ""); + const [categoriesIds, setCategoriesIds] = useState((context?.editContent?.categories ?? []).map(c => c.id)); + const [description, setDescription] = useState(context?.editContent?.description ?? ""); + + const [availableCategories, setAvailableCategories] = useState([]); + useEffect(()=>{ + UniversimeApi.Capacity.categoryList() + .then(response => { + if (response.success && response.body) { + setAvailableCategories(response.body.categories); + } + }) + }, []); + + useEffect(() => { + if (context?.editContent === undefined) + return; + + setName(context.editContent?.name ?? ""); + setDescription(context.editContent?.description ?? ""); + setCategoriesIds((context.editContent?.categories ?? []).map(c => c.id)); + }, [context?.editContent]) + + // prevent later checks + if (!context) + return null; + + if (context.editContent === undefined) + return null; + + const canSave = (name.length > 0) && (description.length > 0); + + return +
+
+ + Nome do Conteúdo +
+ {name.length} / {MAX_NAME_LENGTH} +
+
+ +
+ +
+ + Descrição conteúdo +
+ {description.length} / {MAX_DESC_LENGTH} +
+
+