diff --git a/samples/react-personal-anniversary-counter/package.json b/samples/react-personal-anniversary-counter/package.json index 1d6427190..f996e2f5a 100644 --- a/samples/react-personal-anniversary-counter/package.json +++ b/samples/react-personal-anniversary-counter/package.json @@ -12,31 +12,31 @@ "test": "gulp test" }, "dependencies": { - "tslib": "2.3.1", - "react": "17.0.1", - "react-dom": "17.0.1", "@fluentui/react": "^8.106.4", - "@microsoft/sp-core-library": "1.18.2", "@microsoft/sp-component-base": "1.18.2", + "@microsoft/sp-core-library": "1.18.2", + "@microsoft/sp-lodash-subset": "1.18.2", + "@microsoft/sp-office-ui-fabric-core": "1.18.2", "@microsoft/sp-property-pane": "1.18.2", "@microsoft/sp-webpart-base": "1.18.2", - "@microsoft/sp-lodash-subset": "1.18.2", - "@microsoft/sp-office-ui-fabric-core": "1.18.2" + "react": "17.0.1", + "react-dom": "17.0.1", + "tslib": "2.3.1" }, "devDependencies": { - "@microsoft/rush-stack-compiler-4.7": "0.1.0", - "@rushstack/eslint-config": "2.5.1", - "@microsoft/eslint-plugin-spfx": "1.18.2", "@microsoft/eslint-config-spfx": "1.18.2", + "@microsoft/eslint-plugin-spfx": "1.18.2", + "@microsoft/rush-stack-compiler-4.7": "0.1.0", "@microsoft/sp-build-web": "1.18.2", + "@microsoft/sp-module-interfaces": "1.18.2", + "@rushstack/eslint-config": "2.5.1", + "@types/react": "17.0.45", + "@types/react-dom": "17.0.17", "@types/webpack-env": "~1.15.2", "ajv": "^6.12.5", "eslint": "8.7.0", - "gulp": "4.0.2", - "typescript": "4.7.4", - "@types/react": "17.0.45", - "@types/react-dom": "17.0.17", "eslint-plugin-react-hooks": "4.3.0", - "@microsoft/sp-module-interfaces": "1.18.2" + "gulp": "4.0.2", + "typescript": "4.7.4" } } diff --git a/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/components/PersonalAnniversary.module.scss b/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/components/PersonalAnniversary.module.scss new file mode 100644 index 000000000..c62367089 --- /dev/null +++ b/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/components/PersonalAnniversary.module.scss @@ -0,0 +1,19 @@ +@import '~@fluentui/react/dist/sass/References.scss'; + + +.wrapper { + background: + radial-gradient(circle at 100% 100%, #ffffff 0, #ffffff 6px, transparent 6px) 0% 0%/11px 11px no-repeat, + radial-gradient(circle at 0 100%, #ffffff 0, #ffffff 6px, transparent 6px) 100% 0%/11px 11px no-repeat, + radial-gradient(circle at 100% 0, #ffffff 0, #ffffff 6px, transparent 6px) 0% 100%/11px 11px no-repeat, + radial-gradient(circle at 0 0, #ffffff 0, #ffffff 6px, transparent 6px) 100% 100%/11px 11px no-repeat, + linear-gradient(#ffffff, #ffffff) 50% 50% / calc(100% - 10px) calc(100% - 22px) no-repeat, + linear-gradient(#ffffff, #ffffff) 50% 50% / calc(100% - 22px) calc(100% - 10px) no-repeat, + linear-gradient(325deg, #dfc5e4 0%, #cae4f0 100%); + border-radius: 11px; + padding: 15px; + box-sizing: content-box; + align-items: "center"; + display: "flex"; + flex-direction: "column"; +} diff --git a/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/components/PersonalAnniversary.tsx b/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/components/PersonalAnniversary.tsx index 09a250f1c..99e03dc48 100644 --- a/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/components/PersonalAnniversary.tsx +++ b/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/components/PersonalAnniversary.tsx @@ -1,11 +1,49 @@ import * as React from 'react'; +import useLocalStorage from '../hooks/useLocalStorage'; +import { DatePicker, PrimaryButton, Stack, Text } from '@fluentui/react'; +import styles from './PersonalAnniversary.module.scss'; -export interface IPersonalAnniversaryProps {} +export interface IPersonalAnniversaryProps { } export const PersonalAnniversary: React.FunctionComponent = (props: React.PropsWithChildren) => { + const [date, setDate] = useLocalStorage<{ AnniversaryDate: Date }>('personalAnniversary', null) + const [tempDate, setTempDate] = React.useState(null) + + + if (date === null) + return <> +
+ setTempDate(date)} + value={tempDate} + formatDate={(date) => { + if (date === null) + return '' + return date.toLocaleDateString() + }} + isRequired={true} + /> + setDate({ AnniversaryDate: tempDate })} + disabled={tempDate === null} + /> +
+ + + + const DateDiff: number = new Date().getTime() - date.AnniversaryDate.getTime() return ( <> - +
+ You' ve been working here for: + + {Math.floor(DateDiff / (1000 * 3600 * 24 * 365))} Years + {Math.floor(DateDiff / ((1000 * 3600 * 24 * 365) / 12))} Months + {Math.floor(DateDiff / (1000 * 3600 * 24))} Days + +
); }; \ No newline at end of file diff --git a/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/hooks/useLocalStorage.ts b/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/hooks/useLocalStorage.ts new file mode 100644 index 000000000..9ff21869c --- /dev/null +++ b/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/hooks/useLocalStorage.ts @@ -0,0 +1,20 @@ +import { useState } from 'react'; +import { ObjectHelper } from '../utils/Objecthelper'; + +export default function useLocalStorage(key: string, initialValue?: T): [T, (value: T) => void] { + const [value, setValue] = useState(() => { + const item = window.localStorage.getItem(key); + return item ? ObjectHelper.ParseItem(JSON.parse(item)) : initialValue; + }); + + + const setItem: (newValue: T) => void = (newValue: T) => { + window.localStorage.setItem(key, JSON.stringify(newValue)); + setValue(newValue); + }; + + + return [ + value, setItem + ]; +} \ No newline at end of file diff --git a/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/models/IPersonalAnniversary.ts b/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/models/IPersonalAnniversary.ts new file mode 100644 index 000000000..fa2c120bd --- /dev/null +++ b/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/models/IPersonalAnniversary.ts @@ -0,0 +1,4 @@ +export interface IPersonalAnniversary { + Title: string; + AnniversaryDate: Date; +} \ No newline at end of file diff --git a/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/utils/Objecthelper.ts b/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/utils/Objecthelper.ts new file mode 100644 index 000000000..eedde8dee --- /dev/null +++ b/samples/react-personal-anniversary-counter/src/webparts/personalAnniversary/utils/Objecthelper.ts @@ -0,0 +1,44 @@ +/* eslint-disable */ +export namespace ObjectHelper { + const RemoveODataProperties = (obj: any) => { + for (let prop of Object.keys(obj)) + if (prop.indexOf("odata.") == 0) + delete obj[prop]; + return obj; + } + + + const ISO_8601_FULL = /^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d(\.\d+)?(([+-]\d\d:\d\d)|Z)?$/i + const isISO8601 = (str: string) => (str + "").match(ISO_8601_FULL); + + const ParseAllDates = (obj: any) => { + for (let prop of Object.keys(obj)) + if (isISO8601(obj[prop])) + obj[prop] = new Date(obj[prop]); + return obj; + } + + const RemoveProps: string[] = ["Attachments", "ComplianceAssetId", "FileSystemObjectType", "GUID", "ID", "OData__ColorTag", "OData__UIVersionString", "ServerRedirectedEmbedUri", "ServerRedirectedEmbedUrl"]; + const RemoveDefaultFields = (obj: any) => { + for (let prop of RemoveProps) + delete obj[prop]; + return obj; + } + + + export const ParseItem: (item: T) => T = (item: any) => { + if (Array.isArray(item)) { + for (let i of item) { + i = RemoveODataProperties(i); + i = ParseAllDates(i); + i = RemoveDefaultFields(i); + } + } else { + item = RemoveODataProperties(item); + item = ParseAllDates(item); + item = RemoveDefaultFields(item); + } + return item; + } + +} \ No newline at end of file