Skip to content

Commit

Permalink
feat: Manage Visibility of Collections UI (#140)
Browse files Browse the repository at this point in the history
* chore: added basic

* chore: populate user on creator application

* chore: added status buttons

* chore: make buttons available to only collection owners
  • Loading branch information
Bendomey authored Dec 17, 2024
1 parent 7e296f9 commit 192b8ac
Show file tree
Hide file tree
Showing 9 changed files with 209 additions and 26 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { Button } from '@/components/button/index.tsx'
import { Modal } from '@/components/modal/index.tsx'
import { useDisclosure } from '@/hooks/use-disclosure.tsx'

interface Props {
collection: Collection
}
export function StatusButton({ collection }: Props) {
if (collection.visibility === 'PRIVATE') {
return <PublishButton />
}

return <HideButton />
}

function PublishButton() {
const publishModalState = useDisclosure()

const isSubmitting = false

const handleSubmit = () => {}

return (
<>
<Button onClick={publishModalState.onToggle}>Publish</Button>
<Modal
className="w-full md:w-4/6 lg:w-2/6"
isOpened={publishModalState.isOpened}
onClose={publishModalState.onClose}
>
<div>
<div className="mt-2 grid grid-cols-1">
<h1 className="text-2xl font-bold">Publish "Name of Content"?</h1>
<p className="mt-2 text-sm">
This will make the collection public. You can always hide it.
</p>
</div>
<div className="mt-4 flex justify-end gap-2">
<Button
variant="solid"
color="secondaryGhost"
onClick={publishModalState.onClose}
>
Cancel
</Button>

<Button variant="solid" onClick={handleSubmit}>
{isSubmitting ? 'Publishing...' : 'Publish'}
</Button>
</div>
</div>
</Modal>
</>
)
}

function HideButton() {
const hideModalState = useDisclosure()

const isSubmitting = false

const handleSubmit = () => {}

return (
<>
<Button color="secondaryGhost" onClick={hideModalState.onToggle}>
Hide
</Button>
<Modal
className="w-full md:w-4/6 lg:w-2/6"
isOpened={hideModalState.isOpened}
onClose={hideModalState.onClose}
>
<div>
<div className="mt-2 grid grid-cols-1">
<h1 className="text-2xl font-bold">Hide "Name of Content"?</h1>
<p className="mt-2 text-sm">
This will hide the collection from users. You can always publish
it.
</p>
</div>
<div className="mt-4 flex justify-end gap-2">
<Button
variant="solid"
color="secondaryGhost"
onClick={hideModalState.onClose}
>
Cancel
</Button>

<Button variant="solid" onClick={handleSubmit}>
{isSubmitting ? 'Hiding...' : 'Hide'}
</Button>
</div>
</div>
</Modal>
</>
)
}
59 changes: 51 additions & 8 deletions apps/client/app/modules/collections/single/index.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
import { ArrowPathIcon, ChevronLeftIcon } from '@heroicons/react/24/outline'
import { Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/react'
import {
ArrowPathIcon,
ChevronLeftIcon,
EllipsisHorizontalIcon,
PencilIcon,
} from '@heroicons/react/24/outline'
import { useLoaderData, useNavigate, useParams } from '@remix-run/react'
import dayjs from 'dayjs'
import { useState } from 'react'
import { AddImageContentsModal } from './components/add-image-contents-modal.tsx'
import { RemoveImageContentModal } from './components/remove-image-content-dialog.tsx'
import { StatusButton } from './components/status-button.tsx'
import { useGetCollectionContentsBySlug } from '@/api/collections/index.ts'
import { FadeIn } from '@/components/animation/FadeIn.tsx'
import { Button } from '@/components/button/index.tsx'
Expand Down Expand Up @@ -113,7 +120,7 @@ export function CollectionModule() {
setSelectedCollectionContent(collectionContent)
removeContentsModalState.onToggle()
}}
size="md"
size="sm"
color="dangerGhost"
>
Remove
Expand Down Expand Up @@ -141,13 +148,49 @@ export function CollectionModule() {
<ChevronLeftIcon className="h-4 w-auto" />
Go Back
</Button>
<div className="flex items-end gap-2">
<div className="flex flex-col justify-between gap-3 md:flex-row md:items-start">
<h1 className="text-4xl font-black">{name}</h1>
{isCollectionMine ? (
<span className="inline-flex items-center rounded-md bg-yellow-50 px-2 py-1 text-xs font-medium text-yellow-800 ring-1 ring-inset ring-yellow-600/20">
{collection?.visibility}
</span>
) : null}
<div className="flex items-center gap-3">
{isCollectionMine ? (
<>
<span className="inline-flex items-center rounded-md bg-yellow-50 px-2 py-1 text-xs font-medium text-yellow-800 ring-1 ring-inset ring-yellow-600/20">
{collection?.visibility}
</span>

<StatusButton collection={collection as unknown as Collection} />

<Menu as="div" className="relative">
<div>
<MenuButton>
<Button
variant="unstyled"
className="px-2 hover:bg-zinc-100"
>
<EllipsisHorizontalIcon className="size-6 w-auto" />
</Button>
</MenuButton>
</div>
<MenuItems
transition
className="absolute right-0 z-10 mt-2 w-56 origin-top-right divide-y divide-gray-100 rounded-md bg-white shadow-lg ring-1 ring-black/5 transition focus:outline-none data-[closed]:scale-95 data-[closed]:transform data-[closed]:opacity-0 data-[enter]:duration-100 data-[leave]:duration-75 data-[enter]:ease-out data-[leave]:ease-in"
>
<MenuItem>
<Button
variant="unstyled"
className="flex w-full flex-col flex-wrap items-start rounded-none px-4 py-3 font-medium text-gray-700 data-[focus]:bg-gray-100 data-[focus]:text-gray-900 data-[focus]:outline-none"
>
<div className="flex items-center">
<PencilIcon className="mr-2 size-4" />
<p className="font-bold">Edit Title</p>
</div>
</Button>
</MenuItem>
</MenuItems>
</Menu>
</>
) : null}

</div>
</div>
{collection?.createdBy ? (
<div className="mt-2 flex items-center gap-2">
Expand Down
2 changes: 1 addition & 1 deletion apps/client/app/routes/collections.$collection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export async function loader(loaderArgs: LoaderFunctionArgs) {
filters: {
contentItemsLimit: 2,
},
populate: ['collection.createdBy'],
populate: ['collection.createdBy', 'content'],
},
{
baseUrl,
Expand Down
21 changes: 11 additions & 10 deletions services/main/Controllers/User.cs
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ public async Task<IActionResult> ActiveUserCreatorApplication()
var currentUser = CurrentUser.GetCurrentUser(HttpContext.User.Identity as ClaimsIdentity);
var creatorApplication = await _creatorApplicationService.GetUserActiveCreatorApplication(currentUser.Id);
return new ObjectResult(
new GetEntityResponse<OutputCreatorApplication>(_creatorApplicationTransformer.Transform(creatorApplication), null).Result()
new GetEntityResponse<OutputCreatorApplication>(await _creatorApplicationTransformer.Transform(creatorApplication), null).Result()
)
{ StatusCode = StatusCodes.Status200OK };
}
Expand Down Expand Up @@ -229,7 +229,7 @@ public async Task<IActionResult> CreateCreatorApplication([FromBody] DTOs.Create
var currentUser = CurrentUser.GetCurrentUser(HttpContext.User.Identity as ClaimsIdentity);
var creatorApplication = await _creatorApplicationService.CreateCreatorApplication(input, currentUser.Id);
return new ObjectResult(
new GetEntityResponse<OutputCreatorApplication>(_creatorApplicationTransformer.Transform(creatorApplication), null).Result()
new GetEntityResponse<OutputCreatorApplication>(await _creatorApplicationTransformer.Transform(creatorApplication), null).Result()
)
{ StatusCode = StatusCodes.Status200OK };
}
Expand Down Expand Up @@ -264,7 +264,7 @@ public async Task<IActionResult> UpdateCreatorApplication([FromBody] UpdateCreat
logger.LogInformation($"Update creator application {input}");
var creatorApplication = await _creatorApplicationService.UpdateCreatorApplication(input, id);
return new ObjectResult(
new GetEntityResponse<OutputCreatorApplication>(_creatorApplicationTransformer.Transform(creatorApplication), null).Result()
new GetEntityResponse<OutputCreatorApplication>(await _creatorApplicationTransformer.Transform(creatorApplication), null).Result()
)
{ StatusCode = StatusCodes.Status200OK };
}
Expand Down Expand Up @@ -300,7 +300,7 @@ public async Task<IActionResult> SubmitCreatorApplication(string id)
logger.LogInformation($"submit creator application {id}");
var creatorApplication = await _creatorApplicationService.SubmitCreatorApplication(id);
return new ObjectResult(
new GetEntityResponse<OutputCreatorApplication>(_creatorApplicationTransformer.Transform(creatorApplication), null).Result()
new GetEntityResponse<OutputCreatorApplication>(await _creatorApplicationTransformer.Transform(creatorApplication), null).Result()
)
{ StatusCode = StatusCodes.Status200OK };
}
Expand Down Expand Up @@ -379,7 +379,7 @@ public async Task<IActionResult> RejectCreatorApplication([FromBody] DTOs.Reject
Reason = input.Reason
}, currentAdmin.Id);
return new ObjectResult(
new GetEntityResponse<OutputCreatorApplication>(_creatorApplicationTransformer.Transform(creatorApplication), null).Result()
new GetEntityResponse<OutputCreatorApplication>(await _creatorApplicationTransformer.Transform(creatorApplication), null).Result()
)
{ StatusCode = StatusCodes.Status200OK };
}
Expand Down Expand Up @@ -533,11 +533,12 @@ public async Task<IActionResult> GetCreatorsByAdmin(

long count = await _creatorApplicationService.CountCreatorApplications(status);

var outCreatorApplications = creatorApplications.ConvertAll<OutputCreatorApplication>(
new Converter<CreatorApplication, OutputCreatorApplication>(creatorApplication =>
_creatorApplicationTransformer.Transform(creatorApplication, populate: queryFilter.Populate)
)
);
var outCreatorApplications = new List<OutputCreatorApplication>();
foreach (var creatorApplication in creatorApplications)
{
outCreatorApplications.Add(await _creatorApplicationTransformer.Transform(creatorApplication, populate: queryFilter.Populate));
}

var response = HttpLib.GeneratePagination<OutputCreatorApplication, CreatorApplication>(
outCreatorApplications,
count,
Expand Down
2 changes: 1 addition & 1 deletion services/main/DTOs/OutputCreatorApplication.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ public class OutputCreatorApplication
{
public required string Id { get; set; }
public required string UserId { get; set; }
public OutputUser? User { get; set; }
public OutputBasicUserForAdmin? User { get; set; }
public required string Status { get; set; }
public DateTime? SubmittedAt { get; set; }
public DateTime? RejectedAt { get; set; }
Expand Down
10 changes: 10 additions & 0 deletions services/main/DTOs/OutputUser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ public class OutputBasicUser
public string? Photo { get; set; }
}

public class OutputBasicUserForAdmin
{
public required string Id { get; set; }
public string? Role { get; set; }
public required string Name { get; set; }
public string? Photo { get; set; }
public required string Email { get; set; }
public required string Phone { get; set; }
}

public class OutputBasicCreator
{
public required string Id { get; set; }
Expand Down
1 change: 1 addition & 0 deletions services/main/Lib/PopulateKeys.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ public class PopulateKeys
public static readonly string TAG_CREATED_BY_ADMIN = "tag.createdByAdmin";
public static readonly string CHILD_COLLECTION = "childCollection";
public static readonly string CONTENT_CREATED_BY = "content.createdBy";
public static readonly string USER = "user";
}
27 changes: 21 additions & 6 deletions services/main/Transformations/CreatorApplicationTransformer.cs
Original file line number Diff line number Diff line change
@@ -1,27 +1,42 @@


using main.Domains;
using main.DTOs;
using main.Models;


namespace main.Transformations;

public class CreatorApplicationTransformer
{
public CreatorApplicationTransformer()
private readonly UserService _userService;
private readonly UserTransformer _userTransformer;
public CreatorApplicationTransformer(
UserService userService,
UserTransformer userTransformer
)
{
_userService = userService;
_userTransformer = userTransformer;
}

public OutputCreatorApplication Transform(CreatorApplication creatorApplication, string[]? populate = null)
public async Task<OutputCreatorApplication> Transform(CreatorApplication creatorApplication, string[]? populate = null)
{

populate ??= Array.Empty<string>();

OutputBasicUserForAdmin? outputBasicUser = null;
if (creatorApplication.UserId is not null && populate.Any(p => p.Contains(PopulateKeys.USER)))
{
var createdBy = await _userService.GetUserById(creatorApplication.UserId);
if (createdBy is not null)
{
outputBasicUser = _userTransformer.TransformBasicUserForAdmin(createdBy);
}
}

return new OutputCreatorApplication
{
Id = creatorApplication.Id,
UserId = creatorApplication.UserId,
UserId = creatorApplication.UserId!,
User = outputBasicUser,
Status = creatorApplication.Status,
SubmittedAt = creatorApplication.SubmittedAt,
RejectedAt = creatorApplication.RejectedAt,
Expand Down
14 changes: 14 additions & 0 deletions services/main/Transformations/UserTransformer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,5 +83,19 @@ public OutputBasicUser TransformBasicUser(User user)
};
}

public OutputBasicUserForAdmin TransformBasicUserForAdmin(User user)
{

return new OutputBasicUserForAdmin
{
Id = user.Id,
Name = user.Name,
Photo = user.Photo,
Role = user.Role,
Email = user.Email,
Phone = user.PhoneNumber,
};
}

}

0 comments on commit 192b8ac

Please sign in to comment.