diff --git a/samples/react-birthdays/.nvmrc b/samples/react-birthdays/.nvmrc new file mode 100644 index 0000000000..bb52a169c1 --- /dev/null +++ b/samples/react-birthdays/.nvmrc @@ -0,0 +1 @@ +v18.18.2 diff --git a/samples/react-birthdays/README.md b/samples/react-birthdays/README.md index 948adf197d..c0cb4ecbff 100644 --- a/samples/react-birthdays/README.md +++ b/samples/react-birthdays/README.md @@ -61,6 +61,7 @@ email | Text | true * [João Mendes](https://github.com/joaojmendes) * [Sajal Maity](https://github.com/smaity) * [Valeras Narbutas](https://github.com/ValerasNarbutas) +* [Gretchun Kim](https://github.com/gretchunkim) ## Version history @@ -72,6 +73,7 @@ Version|Date|Comments 3.0.0|April 7, 2022 | Upgraded to SPFx 1.14.0 4.0.0|March 6, 2023 | Upgraded to SPFx 1.16.1 5.0.0|October 2, 2024 | Upgraded to SPFx 1.20.0 +5.1.0|January 13,2025 | Edited SPService to ensure current year is used to pull upcoming birthdays ## Minimal Path to Awesome diff --git a/samples/react-birthdays/assets/sample.json b/samples/react-birthdays/assets/sample.json index b0af837183..6dab47cd6e 100644 --- a/samples/react-birthdays/assets/sample.json +++ b/samples/react-birthdays/assets/sample.json @@ -9,7 +9,7 @@ "The Web Part Birthdays shows the upcoming birthdays in the company, the web part reads birthdays from a list located on the tenant\u0027s root site with title \u0022Birthdays.\u0022" ], "creationDateTime": "2019-07-23", - "updateDateTime": "2024-10-02", + "updateDateTime": "2025-01-13", "products": [ "SharePoint" ], @@ -239,6 +239,11 @@ "company": "JP Morgan Chase", "pictureUrl": "https://github.com/smaity.png", "name": "Sajal Maity" + }, + { + "gitHubAccount": "gretchunkim", + "pictureUrl": "https://github.com/gretchunkim.png", + "name": "Azores" } ], "references": [ diff --git a/samples/react-birthdays/src/controls/happyBirthdayCard/HappyBirthdayCard.tsx b/samples/react-birthdays/src/controls/happyBirthdayCard/HappyBirthdayCard.tsx index f961fbcabd..4345f2eaf3 100644 --- a/samples/react-birthdays/src/controls/happyBirthdayCard/HappyBirthdayCard.tsx +++ b/samples/react-birthdays/src/controls/happyBirthdayCard/HappyBirthdayCard.tsx @@ -82,7 +82,7 @@ export class HappyBirthdayCard extends React.Component { ev.preventDefault(); ev.stopPropagation(); diff --git a/samples/react-birthdays/src/controls/happyBirthdayCard/IHappyBirthdayCardProps.ts b/samples/react-birthdays/src/controls/happyBirthdayCard/IHappyBirthdayCardProps.ts index 9e3b73fb05..4a992e701f 100644 --- a/samples/react-birthdays/src/controls/happyBirthdayCard/IHappyBirthdayCardProps.ts +++ b/samples/react-birthdays/src/controls/happyBirthdayCard/IHappyBirthdayCardProps.ts @@ -1,9 +1,9 @@ export interface IHappyBirthdayCardProps { - userName?:string | undefined; - jobDescription?: string; + userName: string; + jobDescription: string; birthday: string; - anniversary: boolean; - userEmail:string; + anniversary?: boolean; congratulationsMsg?: string; - imageTemplate:string; -} + userEmail: string; + imageTemplate: number; // Change this to a number to represent the index of the imageTemplate array +} \ No newline at end of file diff --git a/samples/react-birthdays/src/controls/happybirthday/HappyBirthday.tsx b/samples/react-birthdays/src/controls/happybirthday/HappyBirthday.tsx index 601023cece..d92878eacb 100644 --- a/samples/react-birthdays/src/controls/happybirthday/HappyBirthday.tsx +++ b/samples/react-birthdays/src/controls/happybirthday/HappyBirthday.tsx @@ -12,23 +12,21 @@ export class HappyBirthday extends React.Component { - this.props.users.map((user: IUser) => { - return ( -
- -
- ); - }) + this.props.users.map((user: IUser, index: number) => ( +
+ +
+ )) } ); } } -export default HappyBirthday; diff --git a/samples/react-birthdays/src/controls/happybirthday/IUser.ts b/samples/react-birthdays/src/controls/happybirthday/IUser.ts index bc4a3bc4ec..a3e306ea33 100644 --- a/samples/react-birthdays/src/controls/happybirthday/IUser.ts +++ b/samples/react-birthdays/src/controls/happybirthday/IUser.ts @@ -1,9 +1,9 @@ export interface IUser { - key: string; - userName:string; - jobDescription?: string; - birthday: string; - userEmail: string; - message: string; - anniversary: boolean; + key: string; // Unique key + userName: string; // Name of the user + message: string; // Birthday message + anniversary: boolean; // Anniversary flag + userEmail: string; // User's email address + jobDescription: string; // Job title + birthday: string; // ISO string of the birthday date } diff --git a/samples/react-birthdays/src/services/IUser.ts b/samples/react-birthdays/src/services/IUser.ts index bc4a3bc4ec..434fb37f9d 100644 --- a/samples/react-birthdays/src/services/IUser.ts +++ b/samples/react-birthdays/src/services/IUser.ts @@ -1,9 +1,9 @@ export interface IUser { key: string; - userName:string; - jobDescription?: string; - birthday: string; - userEmail: string; + userName: string; message: string; anniversary: boolean; + userEmail: string; + jobDescription: string; + birthday: string; // ISO string of the birthday } diff --git a/samples/react-birthdays/src/services/SPService.ts b/samples/react-birthdays/src/services/SPService.ts index 79db20cf5f..13b2ef3d84 100644 --- a/samples/react-birthdays/src/services/SPService.ts +++ b/samples/react-birthdays/src/services/SPService.ts @@ -1,64 +1,56 @@ import { WebPartContext } from "@microsoft/sp-webpart-base"; -import { MSGraphClientV3 } from "@microsoft/sp-http"; +import { MSGraphClientV3 } from "@microsoft/sp-http"; import * as moment from 'moment'; export class SPService { - // private graphClient: MSGraphClientV3 = null; private graphClient: MSGraphClientV3; - private birthdayListTitle: string = "Birthdays"; - constructor(private _context: WebPartContext) { + // private birthdayListTitle: string = "Birthdays"; - } - // Get Profiles - public async getPBirthdays(upcommingDays: number): Promise { - let _results, _today: string, _month: number, _day: number; - let _filter: string, _countdays: number, _f:number, _nextYearStart: string; - let _FinalDate: string; + constructor(private _context: WebPartContext) {} + + // Get Birthdays ignoring the year + // eslint-disable-next-line @typescript-eslint/no-explicit-any + public async getPBirthdays(upcomingDays: number): Promise { try { - _results = null; - _today = '2000-' + moment().format('MM-DD'); - _month = parseInt(moment().format('MM')); - _day = parseInt(moment().format('DD')); - _filter = "fields/Birthday ge '" + _today + "'"; - // If we are in December we have to look if there are birthdays in January - // we have to build a condition to select birthday in January based on number of upcommingDays - // we can not use the year for test, the year is always 2000. - console.log(_month); - _countdays = _day + upcommingDays; - _f = 0; - if (_month === 12 && _countdays > 31) { - _nextYearStart = '2000-01-01'; - _FinalDate = '2000-01-'; - _f = _countdays - 31; - _FinalDate = _FinalDate + _f; - _filter = "fields/Birthday ge '" + _today + "' or (fields/Birthday ge '" + _nextYearStart + "' and fields/Birthday le '" + _FinalDate + "')"; - } - else{ - _FinalDate = '2000-'; - if ((_countdays) > 31) { - _f = _countdays - 31; - _month = _month + 1; - _FinalDate = _FinalDate +_month + '-' + _f; - }else{ - _FinalDate = _FinalDate +_month + '-' + _countdays; - } - _filter = "fields/Birthday ge '" + _today + "' and fields/Birthday le '" + _FinalDate + "'"; - } + const today = moment(); + const todayMMDD = today.format('MM-DD'); // Get today's date as MM-DD + const futureMMDD = today.add(upcomingDays, 'days').format('MM-DD'); // Calculate future date this.graphClient = await this._context.msGraphClientFactory.getClient('3'); - _results = await this.graphClient.api(`sites/root/lists('${this.birthdayListTitle}')/items?orderby=Fields/Birthday`) + + // Fetch all birthdays without filtering + const response = await this.graphClient + .api(`sites/root/lists('Birthdays')/items?orderby=fields/Birthday`) .version('v1.0') .expand('fields') - //.top(upcommingDays) - .filter(_filter) .get(); - return _results.value; + // Filter results locally + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const filteredItems = response.value.filter((item: any) => { + const birthday = item.fields.Birthday; + if (!birthday) return false; // Skip if Birthday is missing + const birthdayMMDD = moment(birthday).format('MM-DD'); // Extract MM-DD + if (todayMMDD > futureMMDD) { + // Handle year transition (December to January) + return ( + birthdayMMDD >= todayMMDD || // Later in the current year + birthdayMMDD <= futureMMDD // Earlier in the next year + ); + } else { + // Normal case (same year) + return birthdayMMDD >= todayMMDD && birthdayMMDD <= futureMMDD; + } + }); + + return filteredItems; } catch (error) { - console.dir(error); + console.error("Error fetching birthdays:", error); return Promise.reject(error); } } + } + export default SPService; diff --git a/samples/react-birthdays/src/webparts/Birthdays/BirthdaysWebPart.ts b/samples/react-birthdays/src/webparts/Birthdays/BirthdaysWebPart.ts index 070497f458..3b1d4aef26 100644 --- a/samples/react-birthdays/src/webparts/Birthdays/BirthdaysWebPart.ts +++ b/samples/react-birthdays/src/webparts/Birthdays/BirthdaysWebPart.ts @@ -17,6 +17,7 @@ import { IBirthdaysProps } from './components/IBirthdaysProps'; export interface IBirthdaysWebPartProps { title: string; numberUpcomingDays: number; + // eslint-disable-next-line @typescript-eslint/no-explicit-any template: any; } diff --git a/samples/react-birthdays/src/webparts/Birthdays/components/Birthdays.tsx b/samples/react-birthdays/src/webparts/Birthdays/components/Birthdays.tsx index ee5dc34642..7bd0056f85 100644 --- a/samples/react-birthdays/src/webparts/Birthdays/components/Birthdays.tsx +++ b/samples/react-birthdays/src/webparts/Birthdays/components/Birthdays.tsx @@ -6,6 +6,7 @@ import * as moment from 'moment'; import { IBirthdayState } from './IBirthdaysState'; import SPService from '../../../services/SPService'; import { WebPartTitle } from "@pnp/spfx-controls-react/lib/WebPartTitle"; +// eslint-disable-next-line @typescript-eslint/no-var-requires const imgBackgroundBallons: string = require('../../../assets/ballonsBackgroud.png'); import { Image, ImageFit } from 'office-ui-fabric-react/lib/Image'; import { Label } from 'office-ui-fabric-react/lib/Label'; @@ -23,8 +24,8 @@ export default class Birthdays extends React.Component { + await this.GetUsers(); } public componentDidUpdate(prevProps: IBirthdaysProps, prevState: IBirthdayState): void { @@ -32,7 +33,7 @@ export default class Birthdays extends React.Component { - let _center: any = !this.state.showBirthdays ? "center" : ""; + const _center: React.CSSProperties['textAlign'] = !this.state.showBirthdays ? "center" : undefined; return (
@@ -60,7 +61,7 @@ export default class Birthdays extends React.Component { if (a.birthday > b.birthday) { return 1; @@ -72,7 +73,7 @@ export default class Birthdays extends React.Component { let _otherMonthsBirthdays: IUser[], _dezemberBirthdays: IUser[]; const listItems = await this._spServices.getPBirthdays(this.props.numberUpcomingDays); if (listItems && listItems.length > 0) { @@ -86,14 +87,14 @@ export default class Birthdays extends React.Component { - var _currentMonth = moment(v.birthday, ["MM-DD-YYYY", "YYYY-MM-DD", "DD/MM/YYYY", "MM/DD/YYYY"]).format('MM'); + const _currentMonth = moment(v.birthday, ["MM-DD-YYYY", "YYYY-MM-DD", "DD/MM/YYYY", "MM/DD/YYYY"]).format('MM'); return (_currentMonth === '12'); }); // Sort by birthday date in Dezember month _dezemberBirthdays = this.SortBirthdays(_dezemberBirthdays); // select birthdays != of month 12 _otherMonthsBirthdays = this._users.filter((v) => { - var _currentMonth = moment(v.birthday, ["MM-DD-YYYY", "YYYY-MM-DD", "DD/MM/YYYY", "MM/DD/YYYY"]).format('MM'); + const _currentMonth = moment(v.birthday, ["MM-DD-YYYY", "YYYY-MM-DD", "DD/MM/YYYY", "MM/DD/YYYY"]).format('MM'); return (_currentMonth !== '12'); }); // sort by birthday date