From 95591f3e84fdc44d0f13dfeadadfafead690faa4 Mon Sep 17 00:00:00 2001 From: emmanuel iheanacho Date: Mon, 28 Sep 2026 09:15:51 +0100 Subject: [PATCH 1/3] docs(governance): add communication norms --- Governance/README.md | 2 +- Governance/policies/COMMUNICATION_NORMS.md | 70 ++++++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 Governance/policies/COMMUNICATION_NORMS.md diff --git a/Governance/README.md b/Governance/README.md index 9ed9b34c..4fc1fba0 100644 --- a/Governance/README.md +++ b/Governance/README.md @@ -26,7 +26,7 @@ documents are added and refined over time (tracked as issues): - **Decision-making** — consensus and voting rules, the RFC/proposal process, and decision records. - **Community & conduct** — code of conduct, enforcement, moderation, and conflict - resolution. + resolution, including [communication norms](policies/COMMUNICATION_NORMS.md). - **Contribution governance** — review policy, triage, labels, and roadmap governance. - **Security & disclosure** — vulnerability reporting, embargo, and advisory processes. - **Releases & change** — versioning, release cadence, deprecation, and change policy. diff --git a/Governance/policies/COMMUNICATION_NORMS.md b/Governance/policies/COMMUNICATION_NORMS.md new file mode 100644 index 00000000..273885e2 --- /dev/null +++ b/Governance/policies/COMMUNICATION_NORMS.md @@ -0,0 +1,70 @@ +# Community Communication Norms + +**Version:** 1.0 + +## Purpose and Scope + +These norms set expectations for communication among TeachLink Web contributors, +maintainers, and community members. They apply to project-related communication +in the official channels below. They complement the project's conduct and +security policies; they do not replace them. + +## Official Channels + +- **GitHub Issues** are for actionable bug reports, feature requests, and + project questions that need tracking. +- **GitHub Discussions**, when enabled for this repository, are for open-ended + questions, ideas, and community conversation. If Discussions are unavailable, + use an appropriate issue. +- **Pull requests** are for proposing code or documentation changes and keeping + review feedback and decisions with the proposed change. +- **Security reports** must use the repository's private vulnerability + reporting channel when available. Otherwise, contact a maintainer privately. + Do not publish suspected vulnerabilities, exploit details, credentials, or + personal data in an issue, discussion, or pull request. + +Project decisions and actionable outcomes should be recorded in the relevant +repository issue, discussion, or pull request so they remain accessible and +searchable. Do not share private contact details or sensitive information in +public channels. + +## Tone and Etiquette + +- Be respectful, inclusive, and professional. Critique proposals and work, not + the people behind them. +- Be clear and constructive: provide relevant context, describe the impact, and + suggest a next step when practical. +- Assume good faith, while listening carefully when someone explains that a + message or action caused harm. Correct misunderstandings without personal + attacks or escalation. +- Keep discussion focused and accessible. Avoid repeated messages, personal + call-outs, and cross-posting the same request to pressure a faster response. +- Harassment, discrimination, threats, insults, and deliberate disruption are + not acceptable. Moderation and conduct concerns should be raised privately + with a maintainer rather than argued out in a public thread. + +## Response Expectations + +TeachLink Web is maintained across time zones and availability varies. The +following are targets, not guarantees or on-call commitments: + +- A maintainer should aim to acknowledge a new issue or discussion within three + business days. +- A pull request should aim to receive an initial review or status update within + five business days. +- If a response is delayed, contributors should add one concise follow-up to the + original thread after five business days. Avoid repeated pings; maintainers + will update the thread when they can. +- Security reports should be acknowledged promptly through the private channel, + but are handled under the security response process rather than these public + response targets. + +Business-day targets do not require anyone to respond outside their normal +availability. If a request is time-sensitive, explain the reason and impact in +the original thread without implying guaranteed priority. + +## Ownership and Changes + +Maintainers own this policy. Changes are proposed through a pull request that +touches only the `Governance/` folder, in accordance with the governance +contribution rules. \ No newline at end of file From 5f1a628d374b78a96f008f3cb6dcf20866a39831 Mon Sep 17 00:00:00 2001 From: emmanuel iheanacho Date: Mon, 28 Sep 2026 09:22:58 +0100 Subject: [PATCH 2/3] fix: resolve header wallet and toast imports --- src/components/layout/HeaderComponent.tsx | 4 ++-- src/components/layout/__tests__/HeaderComponent.test.tsx | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/layout/HeaderComponent.tsx b/src/components/layout/HeaderComponent.tsx index b9bdea10..6192af82 100644 --- a/src/components/layout/HeaderComponent.tsx +++ b/src/components/layout/HeaderComponent.tsx @@ -2,8 +2,8 @@ import { useEffect, useState, useMemo, startTransition } from 'react'; import Link from 'next/link'; -import { toast } from 'sonner'; -import { useWallet } from '@/hooks/useWallet'; +import { toast } from 'react-hot-toast'; +import { useWallet } from '@/providers/WalletProvider'; import { IGrantContext } from '@/types/grants'; import { createLogger } from '@/lib/logging'; diff --git a/src/components/layout/__tests__/HeaderComponent.test.tsx b/src/components/layout/__tests__/HeaderComponent.test.tsx index 840762b6..f5ff03ca 100644 --- a/src/components/layout/__tests__/HeaderComponent.test.tsx +++ b/src/components/layout/__tests__/HeaderComponent.test.tsx @@ -1,9 +1,9 @@ import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { vi, describe, it, expect, beforeEach } from 'vitest'; import HeaderComponent from '../HeaderComponent'; -import { useWallet } from '@/hooks/useWallet'; +import { useWallet } from '@/providers/WalletProvider'; -vi.mock('@/hooks/useWallet', () => ({ +vi.mock('@/providers/WalletProvider', () => ({ useWallet: vi.fn(), })); @@ -57,7 +57,7 @@ describe('HeaderComponent — Grant Management Pipeline Verification', () => { const dropdownButton = await screen.findByText('1 Scope Grant Authorized'); fireEvent.click(dropdownButton); - expect(screen.getByText('BUDGET MANAGEMENT')).toBeInTheDocument(); + expect(screen.getByText('budget management')).toBeInTheDocument(); // Mock successful revocation endpoint cycle (global.fetch as any).mockResolvedValueOnce({ ok: true }); @@ -66,7 +66,7 @@ describe('HeaderComponent — Grant Management Pipeline Verification', () => { fireEvent.click(revokeButton); await waitFor(() => { - expect(screen.queryByText('BUDGET MANAGEMENT')).not.toBeInTheDocument(); + expect(screen.queryByText('budget management')).not.toBeInTheDocument(); }); }); }); From e91dab168aa46dce74e74519b29b6d147dba57e3 Mon Sep 17 00:00:00 2001 From: emmanuel iheanacho Date: Mon, 28 Sep 2026 09:39:03 +0100 Subject: [PATCH 3/3] fix: resolve wallet and sonner type-check errors --- package.json | 1 + pnpm-lock.yaml | 20 +++++++++++++++++++ src/components/layout/HeaderComponent.tsx | 2 +- .../layout/__tests__/HeaderComponent.test.tsx | 4 ++-- src/hooks/useWallet.ts | 11 ++++++++++ src/providers/WalletProvider.tsx | 4 ++-- 6 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 src/hooks/useWallet.ts diff --git a/package.json b/package.json index 4f688132..880aec8c 100644 --- a/package.json +++ b/package.json @@ -88,6 +88,7 @@ "recharts": "^2.15.4", "socket.io": "^4.8.3", "socket.io-client": "^4.8.3", + "sonner": "^2.0.8", "tailwind-merge": "^2.6.0", "uuid": "^14.0.1", "video.js": "^8.23.7", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ca5ffc75..a30bf8ca 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -163,6 +163,9 @@ importers: socket.io-client: specifier: ^4.8.3 version: 4.8.3 + sonner: + specifier: ^2.0.8 + version: 2.0.8(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) tailwind-merge: specifier: ^2.6.0 version: 2.6.1 @@ -6890,6 +6893,16 @@ packages: sonic-boom@4.2.1: resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} + sonner@2.0.8: + resolution: {integrity: sha512-UM/ByIoFra8yzV75n1o0Puu0bw5U/9UNnDacrJNspekBewIfsQ3D6ez1nvlWpt7aTsO6rujQtifBpycwIivqlg==} + peerDependencies: + '@types/react': ^18.0.0 || ^19.0.0 + react: ^18.3.1 + react-dom: ^18.3.1 + peerDependenciesMeta: + '@types/react': + optional: true + source-list-map@2.0.1: resolution: {integrity: sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==} @@ -15970,6 +15983,13 @@ snapshots: dependencies: atomic-sleep: 1.0.0 + sonner@2.0.8(@types/react@18.3.29)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): + dependencies: + react: 18.3.1 + react-dom: 18.3.1(react@18.3.1) + optionalDependencies: + '@types/react': 18.3.29 + source-list-map@2.0.1: {} source-map-js@1.2.1: {} diff --git a/src/components/layout/HeaderComponent.tsx b/src/components/layout/HeaderComponent.tsx index 6192af82..e9fea3e8 100644 --- a/src/components/layout/HeaderComponent.tsx +++ b/src/components/layout/HeaderComponent.tsx @@ -3,7 +3,7 @@ import { useEffect, useState, useMemo, startTransition } from 'react'; import Link from 'next/link'; import { toast } from 'react-hot-toast'; -import { useWallet } from '@/providers/WalletProvider'; +import { useWallet } from '@/hooks/useWallet'; import { IGrantContext } from '@/types/grants'; import { createLogger } from '@/lib/logging'; diff --git a/src/components/layout/__tests__/HeaderComponent.test.tsx b/src/components/layout/__tests__/HeaderComponent.test.tsx index f5ff03ca..8bdbb7fa 100644 --- a/src/components/layout/__tests__/HeaderComponent.test.tsx +++ b/src/components/layout/__tests__/HeaderComponent.test.tsx @@ -1,9 +1,9 @@ import { render, screen, fireEvent, waitFor } from '@testing-library/react'; import { vi, describe, it, expect, beforeEach } from 'vitest'; import HeaderComponent from '../HeaderComponent'; -import { useWallet } from '@/providers/WalletProvider'; +import { useWallet } from '@/hooks/useWallet'; -vi.mock('@/providers/WalletProvider', () => ({ +vi.mock('@/hooks/useWallet', () => ({ useWallet: vi.fn(), })); diff --git a/src/hooks/useWallet.ts b/src/hooks/useWallet.ts new file mode 100644 index 00000000..3b381bcb --- /dev/null +++ b/src/hooks/useWallet.ts @@ -0,0 +1,11 @@ +import { useWallet as useWalletContext } from '@/providers/WalletProvider'; + +export function useWallet() { + const wallet = useWalletContext(); + + return { + ...wallet, + connected: wallet.isConnected, + publicKey: wallet.address, + }; +} \ No newline at end of file diff --git a/src/providers/WalletProvider.tsx b/src/providers/WalletProvider.tsx index be133c9c..bb924201 100644 --- a/src/providers/WalletProvider.tsx +++ b/src/providers/WalletProvider.tsx @@ -72,10 +72,10 @@ export function WalletProvider({ children }: WalletProviderProps) { network: validateWalletEnv().network, })); - const connect = useCallback(async () => { + const connect = useCallback(async (): Promise => { setState((prev) => ({ ...prev, isConnecting: true, error: null })); - return walletConnectionQueue.enqueue(async () => { + await walletConnectionQueue.enqueue(async () => { try { if (typeof window === 'undefined') { throw new Error('Window not available');