diff --git a/.gitignore b/.gitignore index 4d29575..0636399 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,11 @@ npm-debug.log* yarn-debug.log* yarn-error.log* +.vs/CommBank-Web/FileContentIndex/8d2c356b-6d55-4bc1-b87f-f946bbc7b78d.vsidx +.vs/CommBank-Web/FileContentIndex/9249bc86-b3ba-4f44-b8e5-ec4717f093a5.vsidx +.vs/CommBank-Web/FileContentIndex/9a5f6c10-30e5-4065-bf50-dc266c0ea273.vsidx +.vs/CommBank-Web/FileContentIndex/b18f3d19-3f42-463c-a5e3-e9f8fcc8379e.vsidx +.vs/CommBank-Web/FileContentIndex/561213b1-588c-465b-8922-a283db3d4612.vsidx +.vs/CommBank-Web/FileContentIndex/ef1c54a5-c862-4eb4-81f7-7d1f36b54753.vsidx +.vs/CommBank-Web/FileContentIndex/5d1ec056-5fd5-49a8-b029-33a18581789e.vsidx +.vs/CommBank-Web/FileContentIndex/65c1dc03-737d-47f2-9a75-e28d0eb22ce4.vsidx diff --git a/.vs/CommBank-Web/FileContentIndex/3e7f5092-41fa-4b2c-b07a-268730b5fca3.vsidx b/.vs/CommBank-Web/FileContentIndex/3e7f5092-41fa-4b2c-b07a-268730b5fca3.vsidx new file mode 100644 index 0000000..37e0d36 Binary files /dev/null and b/.vs/CommBank-Web/FileContentIndex/3e7f5092-41fa-4b2c-b07a-268730b5fca3.vsidx differ diff --git a/.vs/CommBank-Web/FileContentIndex/548d7493-f6f8-4f26-9905-9e87f41b003a.vsidx b/.vs/CommBank-Web/FileContentIndex/548d7493-f6f8-4f26-9905-9e87f41b003a.vsidx new file mode 100644 index 0000000..dc52c04 Binary files /dev/null and b/.vs/CommBank-Web/FileContentIndex/548d7493-f6f8-4f26-9905-9e87f41b003a.vsidx differ diff --git a/.vs/CommBank-Web/FileContentIndex/9a5f6c10-30e5-4065-bf50-dc266c0ea273.vsidx b/.vs/CommBank-Web/FileContentIndex/9a5f6c10-30e5-4065-bf50-dc266c0ea273.vsidx new file mode 100644 index 0000000..a7d76f1 Binary files /dev/null and b/.vs/CommBank-Web/FileContentIndex/9a5f6c10-30e5-4065-bf50-dc266c0ea273.vsidx differ diff --git a/.vs/CommBank-Web/FileContentIndex/c39b0b38-2d89-450c-9998-6842f79d01aa.vsidx b/.vs/CommBank-Web/FileContentIndex/c39b0b38-2d89-450c-9998-6842f79d01aa.vsidx new file mode 100644 index 0000000..a7d76f1 Binary files /dev/null and b/.vs/CommBank-Web/FileContentIndex/c39b0b38-2d89-450c-9998-6842f79d01aa.vsidx differ diff --git a/.vs/CommBank-Web/FileContentIndex/c3dd5793-81fd-4385-b601-ee2cfd68cde3.vsidx b/.vs/CommBank-Web/FileContentIndex/c3dd5793-81fd-4385-b601-ee2cfd68cde3.vsidx new file mode 100644 index 0000000..7d45a12 Binary files /dev/null and b/.vs/CommBank-Web/FileContentIndex/c3dd5793-81fd-4385-b601-ee2cfd68cde3.vsidx differ diff --git a/.vs/CommBank-Web/config/applicationhost.config b/.vs/CommBank-Web/config/applicationhost.config new file mode 100644 index 0000000..269dc55 --- /dev/null +++ b/.vs/CommBank-Web/config/applicationhost.config @@ -0,0 +1,1021 @@ + + + + + + + + +
+
+
+
+
+
+
+
+ + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+
+
+
+ +
+
+
+ +
+
+ +
+
+ +
+
+
+ + +
+
+
+
+
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.vs/CommBank-Web/v17/.wsuo b/.vs/CommBank-Web/v17/.wsuo new file mode 100644 index 0000000..0ee45a4 Binary files /dev/null and b/.vs/CommBank-Web/v17/.wsuo differ diff --git a/.vs/ProjectSettings.json b/.vs/ProjectSettings.json new file mode 100644 index 0000000..f8b4888 --- /dev/null +++ b/.vs/ProjectSettings.json @@ -0,0 +1,3 @@ +{ + "CurrentProjectSetting": null +} \ No newline at end of file diff --git a/.vs/slnx.sqlite b/.vs/slnx.sqlite new file mode 100644 index 0000000..a451a10 Binary files /dev/null and b/.vs/slnx.sqlite differ diff --git a/README.md b/README.md index b7bff5b..54db531 100644 --- a/README.md +++ b/README.md @@ -1 +1,2 @@ -# CommBank Goal Tracker \ No newline at end of file +# CommBank Goal Tracker +#https://github.com/rezhang1128/CommBank-Web.git \ No newline at end of file diff --git a/Task3_link.html b/Task3_link.html new file mode 100644 index 0000000..ee78af0 --- /dev/null +++ b/Task3_link.html @@ -0,0 +1,3 @@ +I don't know why I can't submit tsx file +So I have to submit the link of the github to show my work +https://github.com/rezhang1128/CommBank-Web.git \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 240aecf..94349f8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6611,6 +6611,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/emoji-mart/-/emoji-mart-3.0.1.tgz", "integrity": "sha512-sxpmMKxqLvcscu6mFn9ITHeZNkGzIvD0BSNFE/LJESPbCA8s1jM6bCDPjWbV31xHq7JXaxgpHxLB54RCbBZSlg==", + "license": "BSD-3-Clause", "dependencies": { "@babel/runtime": "^7.0.0", "prop-types": "^15.6.0" diff --git a/src/api/types.ts b/src/api/types.ts index f75edad..7e3f015 100644 --- a/src/api/types.ts +++ b/src/api/types.ts @@ -26,7 +26,8 @@ export interface Goal { created: Date accountId: string transactionIds: string[] - tagIds: string[] + tagIds: string[] + icon: string | null } export interface Tag { diff --git a/src/test/GoalControllerTests.cs b/src/test/GoalControllerTests.cs new file mode 100644 index 0000000..4cda237 --- /dev/null +++ b/src/test/GoalControllerTests.cs @@ -0,0 +1,40 @@ +using System.Threading.Tasks; +using Xunit; +using Microsoft.AspNetCore.Http; + +public class GoalControllerTests +{ + private readonly FakeCollections collections; + + public GoalControllerTests() + { + collections = new(); + } + + [Fact] + public async Task GetForUser() + { + // Arrange + var goals = collections.GetGoals(); + var users = collections.GetUsers(); + IGoalsService goalsService = new FakeGoalsService(goals, goals[0]); + IUsersService usersService = new FakeUsersService(users, users[0]); + GoalController controller = new(goalsService, usersService); + + var httpContext = new DefaultHttpContext(); + controller.ControllerContext.HttpContext = httpContext; + + // Act + var result = await controller.GetForUser(goals[0].UserId!); + + // Assert + Assert.NotNull(result); + Assert.NotEmpty(result); // Ensure goals exist + + Assert.All(result!, goal => + { + Assert.IsAssignableFrom(goal); + Assert.Equal(goals[0].UserId, goal.UserId); + }); + } +} diff --git a/src/ui/features/goalmanager/GoalManager.tsx b/src/ui/features/goalmanager/GoalManager.tsx index 0779dda..1c7aa56 100644 --- a/src/ui/features/goalmanager/GoalManager.tsx +++ b/src/ui/features/goalmanager/GoalManager.tsx @@ -1,4 +1,3 @@ -import { faCalendarAlt } from '@fortawesome/free-regular-svg-icons' import { faDollarSign, IconDefinition } from '@fortawesome/free-solid-svg-icons' import { FontAwesomeIcon } from '@fortawesome/react-fontawesome' import { MaterialUiPickersDate } from '@material-ui/pickers/typings/date' @@ -11,16 +10,30 @@ import { selectGoalsMap, updateGoal as updateGoalRedux } from '../../../store/go import { useAppDispatch, useAppSelector } from '../../../store/hooks' import DatePicker from '../../components/DatePicker' import { Theme } from '../../components/Theme' +import { BaseEmoji, Picker } from 'emoji-mart'; +import { selectMode } from '../../../store/themeSlice'; +import GoalIcon from './GoalIcon'; +import { TransparentButton } from '../../components/TransparentButton'; +import { faCalendarAlt, faSmile } from '@fortawesome/free-regular-svg-icons'; + type Props = { goal: Goal } +const EmojiPicker = ({ onClick }: { onClick: (emoji: BaseEmoji, event: React.MouseEvent) => void }) => { + const theme = useAppSelector(selectMode); + return ( + + ); +}; + export function GoalManager(props: Props) { const dispatch = useAppDispatch() - const goal = useAppSelector(selectGoalsMap)[props.goal.id] - const [name, setName] = useState(null) const [targetDate, setTargetDate] = useState(null) - const [targetAmount, setTargetAmount] = useState(null) + const [targetAmount, setTargetAmount] = useState(null) + const [icon, setIcon] = useState(props.goal.icon ?? null); +const [emojiPickerIsOpen, setEmojiPickerIsOpen] = useState(false) + useEffect(() => { setName(props.goal.name) @@ -36,6 +49,27 @@ export function GoalManager(props: Props) { useEffect(() => { setName(goal.name) }, [goal.name]) + const hasIcon = () => icon != null; + const addIconOnClick = (event: React.MouseEvent) => { + event.stopPropagation(); + setEmojiPickerIsOpen(true); + }; + const pickEmojiOnClick = (emoji: BaseEmoji, event: React.MouseEvent) => { + event.stopPropagation(); + setIcon(emoji.native); + setEmojiPickerIsOpen(false); + + const updatedGoal: Goal = { + ...props.goal, + icon: emoji.native ?? props.goal.icon, + name: name ?? props.goal.name, + targetDate: targetDate ?? props.goal.targetDate, + targetAmount: targetAmount ?? props.goal.targetAmount, + }; + + dispatch(updateGoalRedux(updatedGoal)); + updateGoalApi(props.goal.id, updatedGoal); + }; const updateNameOnChange = (event: React.ChangeEvent) => { const nextName = event.target.value @@ -105,7 +139,20 @@ export function GoalManager(props: Props) { {new Date(props.goal.created).toLocaleDateString()} - + + + + + + + + + Add icon + + + e.stopPropagation()}> + + ) } @@ -122,6 +169,19 @@ const Field = (props: FieldProps) => ( ) + +const GoalIconContainer = styled.div<{ shouldShow: boolean }>` + display: ${(props) => (props.shouldShow ? 'flex' : 'none')}; +`; + +const AddIconButtonContainer = styled.div<{ hasIcon: boolean }>` + display: ${(props) => (props.hasIcon ? 'none' : 'flex')}; +`; + +const AddIconButtonText = styled.span` + margin-left: 0.5rem; +`; + const GoalManagerContainer = styled.div` display: flex; flex-direction: column; @@ -182,3 +242,10 @@ const StringInput = styled.input` const Value = styled.div` margin-left: 2rem; ` + +const EmojiPickerContainer = styled.div` + display: ${(props) => (props.isOpen ? 'flex' : 'none')}; + position: absolute; + top: ${(props) => (props.hasIcon ? '10rem' : '2rem')}; + left: 0; +` diff --git a/src/ui/pages/Main/goals/GoalCard.tsx b/src/ui/pages/Main/goals/GoalCard.tsx index e8f6d0a..03b7105 100644 --- a/src/ui/pages/Main/goals/GoalCard.tsx +++ b/src/ui/pages/Main/goals/GoalCard.tsx @@ -10,7 +10,9 @@ import { import { Card } from '../../../components/Card' type Props = { id: string } - +const Icon = styled.h1` + font-size: 5.5rem; +` export default function GoalCard(props: Props) { const dispatch = useAppDispatch() @@ -28,7 +30,8 @@ export default function GoalCard(props: Props) { return ( ${goal.targetAmount} - {asLocaleDateString(goal.targetDate)} + {asLocaleDateString(goal.targetDate)} + {goal.icon} ) }