Skip to content

Commit

Permalink
rebased 2
Browse files Browse the repository at this point in the history
  • Loading branch information
elraphty committed May 24, 2024
1 parent 08f3c19 commit 6731b3e
Show file tree
Hide file tree
Showing 10 changed files with 364 additions and 16 deletions.
5 changes: 5 additions & 0 deletions .idea/.gitignore

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/inspectionProfiles/Project_Default.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 12 additions & 0 deletions .idea/sphinx-tribes-frontend.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

34 changes: 29 additions & 5 deletions cypress/e2e/58_addUserStoriesToFeature.cy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ describe('Add user stories to features', () => {
cy.login('carol');
cy.wait(1000);

const WorkSpaceName = 'user story';
const WorkSpaceName = 'user story8';

const workspace = {
loggedInAs: 'carol',
Expand Down Expand Up @@ -46,12 +46,36 @@ describe('Add user stories to features', () => {
cy.wait(1000);

const userStory = 'this is the story of a user';
cy.get('[data-testid="story-input"]').type(userStory);
cy.get('[data-testid="story-input-update-btn"]').click();
for (let i = 1; i <= 2; i++) {
const userStoryWithNumber = `${userStory} ${i}`;
cy.get('[data-testid="story-input"]').type(userStoryWithNumber);
cy.get('[data-testid="story-input-update-btn"]').click();
cy.wait(1000);

cy.contains(userStoryWithNumber).should('exist', { timeout: 1000 });
cy.wait(1000);
}

cy.get('[data-testid="0-user-story-option-btn"]').click();
cy.get('[data-testid="user-story-edit-btn"]').click();
cy.wait(1000);
cy.get('[data-testid="edit-story-input"]').clear();
const updatedUserStory = 'this is the story of a user changed';
cy.get('[data-testid="edit-story-input"]').type(updatedUserStory);
cy.get('[data-testid="user-story-save-btn"]').click();
cy.wait(1000);

cy.contains(updatedUserStory).should('exist', { timeout: 1000 });

cy.contains(userStory).should('exist', { timeout: 1000 });
cy.wait(5000);
cy.get('[data-testid="1-user-story-option-btn"]').click();
cy.get('[data-testid="user-story-edit-btn"]').click();
cy.wait(1000);
cy.get('[data-testid="user-story-delete-btn"]').click();
cy.wait(1000);
cy.contains('Delete').click({ force: true });
cy.wait(1000);
const userStoryWithNumber = `${userStory} ${2}`;
cy.contains(userStoryWithNumber).should('not.exist', { timeout: 1000 });
cy.logout('carol');
});
});
18 changes: 18 additions & 0 deletions src/pages/tickets/style.ts
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,24 @@ export const OptionsWrap = styled.div`
}
`;

export const UserStoryOptionWrap = styled.div`
position: relative;
display: inline-block;
cursor: pointer;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 5px;
button {
border: 0.5px solid #000000;
font-size: 0.8rem;
font-weight: 700;
border-radius: 5px;
padding: 2px 10px;
}
`;
export const TextArea = styled.textarea`
padding: 0.5rem 1rem;
border-radius: 0.375rem;
Expand Down
198 changes: 188 additions & 10 deletions src/people/widgetViews/WorkspaceFeature.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,19 @@ import {
OptionsWrap,
TextArea,
InputField,
Input
Input,
UserStoryOptionWrap
} from 'pages/tickets/style';
import React, { useCallback, useEffect, useState } from 'react';
import history from 'config/history';
import { useParams } from 'react-router-dom';
import { useStores } from 'store';
import { mainStore } from 'store/main';
import { Feature } from 'store/interface';
import { Feature, FeatureStory } from 'store/interface';
import MaterialIcon from '@material/react-material-icon';
import { FeatureStory } from 'store/interface';
import { EuiOverlayMask, EuiModalHeader, EuiModalFooter, EuiText } from '@elastic/eui';
import { Box } from '@mui/system';
import { useDeleteConfirmationModal } from '../../components/common';
import {
ActionButton,
ButtonWrap,
Expand All @@ -27,7 +30,12 @@ import {
WorkspaceName,
WorkspaceOption,
UserStoryField,
UserStoryFields
UserStoryFields,
UserStoryOption,
StyledModal,
ModalBody,
ButtonGroup,
StoryButtonWrap
} from './workspace/style';

type DispatchSetStateAction<T> = React.Dispatch<React.SetStateAction<T>>;
Expand Down Expand Up @@ -175,6 +183,81 @@ const WorkspaceEditableField = ({
);
};

interface UserStoryModalProps {
open: boolean;
storyDescription: string;
handleClose: () => void;
handleSave: (inputValue: string) => void;
handleDelete: () => void;
}

const UserStoryModal: React.FC<UserStoryModalProps> = ({
open,
storyDescription,
handleClose,
handleSave,
handleDelete
}: UserStoryModalProps) => {
const [inputValue, setInputValue] = useState<string>(storyDescription);

useEffect(() => {
setInputValue(storyDescription);
}, [storyDescription]);
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setInputValue(event.target.value);
};

return (
<>
{open && (
<EuiOverlayMask>
<StyledModal>
<EuiModalHeader>
<EuiText>
<h2>Edit User Story</h2>
</EuiText>
</EuiModalHeader>
<ModalBody>
<Label>User Story</Label>
<Input
placeholder="Edit Story"
onChange={handleInputChange}
value={inputValue}
data-testid="edit-story-input"
/>
</ModalBody>
<EuiModalFooter>
<ButtonGroup>
<StoryButtonWrap>
<ActionButton
borderRadius="50px"
data-testid="user-story-save-btn"
onClick={() => handleSave(inputValue)}
>
Save
</ActionButton>
<ActionButton borderRadius="50px" color="cancel" onClick={handleClose}>
Cancel
</ActionButton>
</StoryButtonWrap>
<ActionButton
borderRadius="50px"
data-testid="user-story-delete-btn"
marginTop="30px"
color="cancel"
onClick={handleDelete}
>
Delete
</ActionButton>
</ButtonGroup>
</EuiModalFooter>
</StyledModal>
</EuiOverlayMask>
)}
</>
);
};

const WorkspaceFeature: React.FC = () => {
const { main, ui } = useStores();
const { feature_uuid } = useParams<{ feature_uuid: string }>();
Expand All @@ -192,6 +275,11 @@ const WorkspaceFeature: React.FC = () => {
const [displayBriefOptions, setDisplayBriefOptions] = useState<boolean>(false);
const [displayArchitectureOptions, setDisplayArchitectureOptions] = useState<boolean>(false);
const [displayRequirementsOptions, setDisplayRequirementsOptions] = useState<boolean>(false);
const [displayUserStoryOptions, setDisplayUserStoryOptions] = useState<Record<number, boolean>>(
{}
);
const [modalOpen, setModalOpen] = useState<boolean>(false);
const [editUserStory, setEditUserStory] = useState<FeatureStory>();

const getFeatureData = useCallback(async (): Promise<void> => {
if (!feature_uuid) return;
Expand Down Expand Up @@ -250,6 +338,69 @@ const WorkspaceFeature: React.FC = () => {
setUserStory(e.target.value);
};

const handleUserStoryOptionClick = (storyId: number) => {
setDisplayUserStoryOptions((prev: Record<number, boolean>) => ({
...prev,
[storyId]: !prev[storyId]
}));
};

const handleUserStoryEdit = (featureStory: FeatureStory) => {
const storyId = featureStory?.id as number;
setEditUserStory(featureStory);
setModalOpen(true);
setDisplayUserStoryOptions((prev: Record<number, boolean>) => ({
...prev,
[storyId]: !prev[storyId]
}));
};

const handleModalClose = () => {
setModalOpen(false);
};

const handleModalSave = async (inputValue: string) => {
const body = {
uuid: editUserStory?.uuid,
feature_uuid: editUserStory?.feature_uuid ?? '',
description: inputValue,
priority: editUserStory?.priority
};
await main.addFeatureStory(body);
await getFeatureStoryData();
setModalOpen(false);
};

const deleteUserStory = async () => {
await main.deleteFeatureStory(
editUserStory?.feature_uuid as string,
editUserStory?.uuid as string
);
await getFeatureStoryData();
return;
};

const { openDeleteConfirmation } = useDeleteConfirmationModal();

const deleteHandler = () => {
openDeleteConfirmation({
onDelete: deleteUserStory,
children: (
<Box fontSize={20} textAlign="center">
Are you sure you want to <br />
<Box component="span" fontWeight="500">
delete this User Story?
</Box>
</Box>
)
});
};

const handleModalDelete = async () => {
setModalOpen(false);
deleteHandler();
};

const toastsEl = (
<EuiGlobalToastList
toasts={ui.toasts}
Expand Down Expand Up @@ -305,12 +456,32 @@ const WorkspaceFeature: React.FC = () => {
</InputField>

<UserStoryFields>
{featureStories?.map((story: FeatureStory) => (
<UserStoryField key={story.id}>
<MaterialIcon icon="more_vert" />
<span>{story.description}</span>
</UserStoryField>
))}
{featureStories
?.sort((a: FeatureStory, b: FeatureStory) => a.priority - b.priority)
?.map((story: FeatureStory) => (
<UserStoryField key={story.id}>
<UserStoryOptionWrap>
<MaterialIcon
icon="more_vert"
onClick={() => handleUserStoryOptionClick(story.id as number)}
data-testid={`${story.priority}-user-story-option-btn`}
/>
{displayUserStoryOptions[story?.id as number] && (
<UserStoryOption>
<ul>
<li
data-testid="user-story-edit-btn"
onClick={() => handleUserStoryEdit(story)}
>
Edit
</li>
</ul>
</UserStoryOption>
)}
</UserStoryOptionWrap>
<span>{story.description}</span>
</UserStoryField>
))}
</UserStoryFields>
</Data>
</FieldWrap>
Expand Down Expand Up @@ -356,6 +527,13 @@ const WorkspaceFeature: React.FC = () => {
/>
</DataWrap>
{toastsEl}
<UserStoryModal
open={modalOpen}
storyDescription={editUserStory?.description as string}
handleClose={handleModalClose}
handleSave={handleModalSave}
handleDelete={handleModalDelete}
/>
</FeatureBody>
);
};
Expand Down
Loading

0 comments on commit 6731b3e

Please sign in to comment.