Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: cycles folder structure #304

Merged
merged 1 commit into from
Feb 20, 2023
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
5 changes: 2 additions & 3 deletions apps/app/components/command-palette/command-pallette.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import { ShortcutsModal } from "components/command-palette";
import { BulkDeleteIssuesModal } from "components/core";
import { CreateProjectModal } from "components/project";
import { CreateUpdateIssueModal } from "components/issues";
import { CreateUpdateCycleModal } from "components/cycles";
import { CreateUpdateModuleModal } from "components/modules";
import CreateUpdateCycleModal from "components/project/cycles/create-update-cycle-modal";
// ui
import { Button } from "components/ui";
// icons
Expand Down Expand Up @@ -169,8 +169,7 @@ export const CommandPalette: React.FC = () => {
<>
<CreateUpdateCycleModal
isOpen={isCreateCycleModalOpen}
setIsOpen={setIsCreateCycleModalOpen}
projectId={projectId as string}
handleClose={() => setIsCreateCycleModalOpen(false)}
/>
<CreateUpdateModuleModal
isOpen={isCreateModuleModalOpen}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
// react
import { useState } from "react";
// components
import SingleStat from "components/project/cycles/stats-view/single-stat";
import ConfirmCycleDeletion from "components/project/cycles/confirm-cycle-deletion";
import { DeleteCycleModal, SingleCycleCard } from "components/cycles";
// types
import { ICycle, SelectCycleType } from "types";
import { CompletedCycleIcon, CurrentCycleIcon, UpcomingCycleIcon } from "components/icons";
Expand All @@ -14,7 +13,7 @@ type TCycleStatsViewProps = {
type: "current" | "upcoming" | "completed";
};

const CycleStatsView: React.FC<TCycleStatsViewProps> = ({
export const CyclesListView: React.FC<TCycleStatsViewProps> = ({
cycles,
setCreateUpdateCycleModal,
setSelectedCycle,
Expand All @@ -35,7 +34,7 @@ const CycleStatsView: React.FC<TCycleStatsViewProps> = ({

return (
<>
<ConfirmCycleDeletion
<DeleteCycleModal
isOpen={
cycleDeleteModal &&
!!selectedCycleForDelete &&
Expand All @@ -46,7 +45,7 @@ const CycleStatsView: React.FC<TCycleStatsViewProps> = ({
/>
{cycles.length > 0 ? (
cycles.map((cycle) => (
<SingleStat
<SingleCycleCard
key={cycle.id}
cycle={cycle}
handleDeleteCycle={() => handleDeleteCycle(cycle)}
Expand All @@ -71,5 +70,3 @@ const CycleStatsView: React.FC<TCycleStatsViewProps> = ({
</>
);
};

export default CycleStatsView;
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ type TConfirmCycleDeletionProps = {
// fetch-keys
import { CYCLE_LIST } from "constants/fetch-keys";

const ConfirmCycleDeletion: React.FC<TConfirmCycleDeletionProps> = ({
export const DeleteCycleModal: React.FC<TConfirmCycleDeletionProps> = ({
isOpen,
setIsOpen,
data,
Expand Down Expand Up @@ -149,5 +149,3 @@ const ConfirmCycleDeletion: React.FC<TConfirmCycleDeletionProps> = ({
</Transition.Root>
);
};

export default ConfirmCycleDeletion;
124 changes: 81 additions & 43 deletions apps/app/components/cycles/form.tsx
Original file line number Diff line number Diff line change
@@ -1,39 +1,59 @@
import { FC } from "react";
import { useEffect } from "react";

// react-hook-form
import { Controller, useForm } from "react-hook-form";
// components
import { Button, Input, TextArea, CustomSelect } from "components/ui";
// ui
import { Button, CustomDatePicker, CustomSelect, Input, TextArea } from "components/ui";
// types
import type { ICycle } from "types";
import { ICycle } from "types";

type Props = {
handleFormSubmit: (values: Partial<ICycle>) => Promise<void>;
handleClose: () => void;
status: boolean;
data?: ICycle;
};

const defaultValues: Partial<ICycle> = {
name: "",
description: "",
status: "draft",
start_date: new Date().toString(),
end_date: new Date().toString(),
start_date: "",
end_date: "",
};

export interface CycleFormProps {
handleFormSubmit: (values: Partial<ICycle>) => void;
handleFormCancel?: () => void;
initialData?: Partial<ICycle>;
}

export const CycleForm: FC<CycleFormProps> = (props) => {
const { handleFormSubmit, handleFormCancel = () => {}, initialData = null } = props;
// form handler
export const CycleForm: React.FC<Props> = ({ handleFormSubmit, handleClose, status, data }) => {
const {
register,
formState: { errors, isSubmitting },
handleSubmit,
control,
reset,
} = useForm<ICycle>({
defaultValues: initialData || defaultValues,
defaultValues,
});

const handleCreateUpdateCycle = async (formData: Partial<ICycle>) => {
await handleFormSubmit(formData);

reset({
...defaultValues,
});
};

useEffect(() => {
reset({
...defaultValues,
...data,
});
}, [data, reset]);

return (
<form onSubmit={handleSubmit(handleFormSubmit)}>
<form onSubmit={handleSubmit(handleCreateUpdateCycle)}>
<div className="space-y-5">
<h3 className="text-lg font-medium leading-6 text-gray-900">
{status ? "Update" : "Create"} Cycle
</h3>
<div className="space-y-3">
<div>
<Input
Expand All @@ -47,6 +67,10 @@ export const CycleForm: FC<CycleFormProps> = (props) => {
register={register}
validations={{
required: "Name is required",
maxLength: {
value: 255,
message: "Name should be less than 255 characters",
},
}}
/>
</div>
Expand Down Expand Up @@ -86,42 +110,56 @@ export const CycleForm: FC<CycleFormProps> = (props) => {
</div>
<div className="flex gap-x-2">
<div className="w-full">
<Input
id="start_date"
label="Start Date"
name="start_date"
type="date"
placeholder="Enter start date"
error={errors.start_date}
register={register}
validations={{
required: "Start date is required",
}}
/>
<h6 className="text-gray-500">Start Date</h6>
<div className="w-full">
<Controller
control={control}
name="start_date"
rules={{ required: "Start date is required" }}
render={({ field: { value, onChange } }) => (
<CustomDatePicker
renderAs="input"
value={value}
onChange={onChange}
error={errors.start_date ? true : false}
/>
)}
/>
{errors.start_date && (
<h6 className="text-sm text-red-500">{errors.start_date.message}</h6>
)}
</div>
</div>
<div className="w-full">
<Input
id="end_date"
label="End Date"
name="end_date"
type="date"
placeholder="Enter end date"
error={errors.end_date}
register={register}
validations={{
required: "End date is required",
}}
/>
<h6 className="text-gray-500">End Date</h6>
<div className="w-full">
<Controller
control={control}
name="end_date"
rules={{ required: "End date is required" }}
render={({ field: { value, onChange } }) => (
<CustomDatePicker
renderAs="input"
value={value}
onChange={onChange}
error={errors.end_date ? true : false}
/>
)}
/>
{errors.end_date && (
<h6 className="text-sm text-red-500">{errors.end_date.message}</h6>
)}
</div>
</div>
</div>
</div>
</div>
<div className="mt-5 flex justify-end gap-2">
<Button theme="secondary" onClick={handleFormCancel}>
<Button theme="secondary" onClick={handleClose}>
Cancel
</Button>
<Button type="submit" disabled={isSubmitting}>
{initialData
{status
? isSubmitting
? "Updating Cycle..."
: "Update Cycle"
Expand Down
6 changes: 5 additions & 1 deletion apps/app/components/cycles/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export * from "./cycles-list-view";
export * from "./delete-cycle-modal";
export * from "./form";
export * from "./modal";
export * from "./select";
export * from "./form";
export * from "./sidebar";
export * from "./single-cycle-card";
64 changes: 32 additions & 32 deletions apps/app/components/cycles/modal.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { Fragment } from "react";

import { useRouter } from "next/router";

import { mutate } from "swr";

// headless ui
Expand All @@ -15,28 +17,27 @@ import type { ICycle } from "types";
// fetch keys
import { CYCLE_LIST } from "constants/fetch-keys";

export interface CycleModalProps {
type CycleModalProps = {
isOpen: boolean;
handleClose: () => void;
projectId: string;
workspaceSlug: string;
initialData?: ICycle;
}
data?: ICycle;
};

export const CycleModal: React.FC<CycleModalProps> = ({
export const CreateUpdateCycleModal: React.FC<CycleModalProps> = ({
isOpen,
handleClose,
initialData,
projectId,
workspaceSlug,
data,
}) => {
const router = useRouter();
const { workspaceSlug, projectId } = router.query;

const { setToastAlert } = useToast();

const createCycle = (payload: Partial<ICycle>) => {
cycleService
.createCycle(workspaceSlug as string, projectId, payload)
const createCycle = async (payload: Partial<ICycle>) => {
await cycleService
.createCycle(workspaceSlug as string, projectId as string, payload)
.then((res) => {
mutate(CYCLE_LIST(projectId));
mutate(CYCLE_LIST(projectId as string));
handleClose();
})
.catch((err) => {
Expand All @@ -48,11 +49,11 @@ export const CycleModal: React.FC<CycleModalProps> = ({
});
};

const updateCycle = (cycleId: string, payload: Partial<ICycle>) => {
cycleService
.updateCycle(workspaceSlug, projectId, cycleId, payload)
const updateCycle = async (cycleId: string, payload: Partial<ICycle>) => {
await cycleService
.updateCycle(workspaceSlug as string, projectId as string, cycleId, payload)
.then((res) => {
mutate(CYCLE_LIST(projectId));
mutate(CYCLE_LIST(projectId as string));
handleClose();
})
.catch((err) => {
Expand All @@ -64,18 +65,15 @@ export const CycleModal: React.FC<CycleModalProps> = ({
});
};

const handleFormSubmit = (formValues: Partial<ICycle>) => {
if (workspaceSlug && projectId) {
const payload = {
...formValues,
};
const handleFormSubmit = async (formData: Partial<ICycle>) => {
if (!workspaceSlug || !projectId) return;

const payload: Partial<ICycle> = {
...formData,
};

if (initialData) {
updateCycle(initialData.id, payload);
} else {
createCycle(payload);
}
}
if (!data) await createCycle(payload);
else await updateCycle(data.id, payload);
};

return (
Expand Down Expand Up @@ -104,10 +102,12 @@ export const CycleModal: React.FC<CycleModalProps> = ({
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
>
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-white px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-gray-900">
{initialData ? "Update" : "Create"} Cycle
</Dialog.Title>
<CycleForm handleFormSubmit={handleFormSubmit} handleFormCancel={handleClose} />
<CycleForm
handleFormSubmit={handleFormSubmit}
handleClose={handleClose}
status={data ? true : false}
data={data}
/>
</Dialog.Panel>
</Transition.Child>
</div>
Expand Down
9 changes: 2 additions & 7 deletions apps/app/components/cycles/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { CyclesIcon } from "components/icons";
// services
import cycleServices from "services/cycles.service";
// components
import { CycleModal } from "components/cycles";
import { CreateUpdateCycleModal } from "components/cycles";
// fetch-keys
import { CYCLE_LIST } from "constants/fetch-keys";

Expand Down Expand Up @@ -54,12 +54,7 @@ export const CycleSelect: React.FC<IssueCycleSelectProps> = ({

return (
<>
<CycleModal
isOpen={isCycleModalActive}
handleClose={closeCycleModal}
projectId={projectId}
workspaceSlug={workspaceSlug as string}
/>
<CreateUpdateCycleModal isOpen={isCycleModalActive} handleClose={closeCycleModal} />
<Listbox as="div" className="relative" value={value} onChange={onChange} multiple={multiple}>
{({ open }) => (
<>
Expand Down
Loading