Skip to content

Commit

Permalink
refactor: add lints from eslint-react, prevent pass-reset w/o admin
Browse files Browse the repository at this point in the history
  • Loading branch information
PThorpe92 committed Oct 26, 2024
1 parent 8e5bc69 commit 171d659
Show file tree
Hide file tree
Showing 20 changed files with 183 additions and 176 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ jobs:
cd frontend && \
corepack install -g yarn && \
yarn && \
yarn lint-staged && \
yarn lint && \
yarn build
94 changes: 48 additions & 46 deletions frontend/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,50 +5,52 @@ import react from 'eslint-plugin-react';
import reactCompiler from 'eslint-plugin-react-compiler';

export default tseslint.config(
{
ignores: [
'eslint.config.mjs',
'tailwind.config.js',
'postcss.config.cjs',
'vite.config.ts',
'dist/**'
]
},
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname
}
}
},
eslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.stylisticTypeChecked,
// These @ts-ignores should go away when https://github.com/jsx-eslint/eslint-plugin-react/issues/3838 is solved
// @ts-ignore
{
// @ts-ignore
...react.configs.flat.recommended,
plugins: {
// @ts-ignore
react,
// React compiler brings rules for react that are going to be solved when the compiler is launched, but is the React recommended way of good practices.
// See: https://react.dev/learn/react-compiler
'react-compiler': reactCompiler
},
settings: {
react: {
version: 'detect'
}
},
// @ts-ignore - React ESLint seems to have issues with typescript-eslint
rules: {
...react.configs.flat.recommended.rules,
'react/react-in-jsx-scope': 'off',
// @ts-ignore
'react/jsx-filename-extension': [1, { extensions: ['.tsx'] }],
'react-compiler/react-compiler': 'warn'
}
}
{
ignores: [
'eslint.config.mjs',
'tailwind.config.js',
'postcss.config.cjs',
'vite.config.ts',
'dist/**',
'node_modules/**'
]
},
{
languageOptions: {
parserOptions: {
projectService: true,
tsconfigRootDir: import.meta.dirname
}
}
},
eslint.configs.recommended,
...tseslint.configs.recommendedTypeChecked,
...tseslint.configs.stylisticTypeChecked,
// These @ts-ignores should go away when https://github.com/jsx-eslint/eslint-plugin-react/issues/3838 is solved
// @ts-ignore
{
// @ts-ignore
...react.configs.flat.recommended,
plugins: {
// @ts-ignore
react,
// React compiler brings rules for react that are going to be solved when the compiler is launched, but is the React recommended way of good practices.
// See: https://react.dev/learn/react-compiler
'react-compiler': reactCompiler
},
settings: {
react: {
version: 'detect'
}
},
// @ts-ignore - React ESLint seems to have issues with typescript-eslint
rules: {
...react.configs.flat.recommended.rules,
'react/react-in-jsx-scope': 'off',
"react/prop-types": "off",
// @ts-ignore
'react/jsx-filename-extension': [1, { extensions: ['.tsx'] }],
'react-compiler/react-compiler': 'warn'
}
}
);
3 changes: 1 addition & 2 deletions frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint-staged": "oxlint src && eslint --fix src",
"lint-staged": "eslint --fix src",
"lint": "eslint .",
"preview": "vite preview",
"prepare": "cd .. && husky frontend/.husky"
Expand All @@ -17,7 +17,6 @@
"axios": "^1.6.8",
"daisyui": "^4.10.5",
"eslint-plugin-prettier": "^5.2.1",
"oxlint": "^0.3.2",
"postcss": "^8.4.38",
"prettier": "^3.2.5",
"react": "^18.2.0",
Expand Down
6 changes: 4 additions & 2 deletions frontend/src/AuthContext.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ import React from 'react';
import { useState, useEffect } from 'react';
import { INIT_KRATOS_LOGIN_FLOW, User } from '@/common';
import { AuthContext, fetchUser } from '@/useAuth';
import { useNavigate } from 'react-router-dom';

export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
children
}) => {
const navigate = useNavigate();
const passReset = '/reset-password';
const [user, setUser] = useState<User | undefined>();
const [loading, setLoading] = useState(true);
Expand All @@ -24,14 +26,14 @@ export const AuthProvider: React.FC<{ children: React.ReactNode }> = ({
return <div></div>;
}
if (!user && !loading) {
window.location.href = INIT_KRATOS_LOGIN_FLOW;
navigate(INIT_KRATOS_LOGIN_FLOW);
return null;
} else if (
!loading &&
user?.password_reset &&
window.location.pathname !== passReset
) {
window.location.href = passReset;
navigate(passReset);
return null;
}
return (
Expand Down
58 changes: 27 additions & 31 deletions frontend/src/Components/CategoryItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -120,37 +120,33 @@ export default function CategoryItem({
</button>
</ul>
{/* Modals */}
{activeLinkToDelete && (
<Modal
type={ModalType.Confirm}
item="Delete Link"
form={
<DeleteForm
item="Link"
onCancel={() => setActiveLinkToDelete(undefined)}
onSuccess={() =>
deleteLink(category, activeLinkToDelete)
}
/>
}
ref={deleteLinkModal}
/>
)}
{addLinkModal.current && (
<Modal
type={ModalType.Add}
item="Link"
form={
<AddLinkForm
onSuccess={(title: string, url: string) => {
addLink(category, title, url);
addLinkModal.current?.close();
}}
/>
}
ref={addLinkModal}
/>
)}
<Modal
type={ModalType.Confirm}
item="Delete Link"
form={
<DeleteForm
item="Link"
onCancel={() => setActiveLinkToDelete(undefined)}
onSuccess={() =>
deleteLink(category, activeLinkToDelete!)
}
/>
}
ref={deleteLinkModal}
/>
<Modal
type={ModalType.Add}
item="Link"
form={
<AddLinkForm
onSuccess={(title: string, url: string) => {
addLink(category, title, url);
addLinkModal.current?.close();
}}
/>
}
ref={addLinkModal}
/>
</details>
);
}
44 changes: 22 additions & 22 deletions frontend/src/Components/LibraryLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,21 @@ export default function LibaryLayout({
studentView?: boolean;
}) {
const { user } = useAuth();
if (!user) {
return null;
}
const [searchTerm, setSearchTerm] = useState<string>('');
const [perPage, setPerPage] = useState(20);
const [pageQuery, setPageQuery] = useState<number>(1);
const allLibrariesTab: Tab = {
name: 'All',
value: 'all'
};
let role = user?.role ?? UserRole.Student;
const [activeTab, setActiveTab] = useState<Tab>(allLibrariesTab);
const [filterLibraries, setFilterLibraries] = useState<string>(
FilterLibraries['All Libraries']
);
const [filterLibrariesAdmin, setFilterLibrariesAdmin] = useState<string>(
FilterLibrariesAdmin['All Libraries']
);
let role = user.role;
if (studentView) {
role = UserRole.Student;
}
const [perPage, setPerPage] = useState(20);
const [pageQuery, setPageQuery] = useState<number>(1);
const {
data: libraries,
mutate: mutateLibraries,
Expand All @@ -55,21 +49,8 @@ export default function LibaryLayout({
} = useSWR<ServerResponseMany<Library>, AxiosError>(
`/api/libraries?page=${pageQuery}&per_page=${perPage}&visibility=${role == UserRole.Admin ? filterLibrariesAdmin : studentView ? 'visible' : filterLibraries}&search=${searchTerm}`
);
const librariesMeta = libraries?.meta ?? {
total: 0,
per_page: 20,
page: 1,
current_page: 1,
last_page: 1
};

const { data: openContentProviders } =
useSWR<ServerResponseMany<OpenContentProvider>>('/api/open-content');
const handleSetPerPage = (perPage: number) => {
setPerPage(perPage);
setPageQuery(1);
void mutateLibraries();
};
const openContentTabs = useMemo(() => {
return [
allLibrariesTab,
Expand All @@ -85,6 +66,25 @@ export default function LibaryLayout({
useEffect(() => {
setPageQuery(1);
}, [filterLibrariesAdmin, filterLibraries, searchTerm]);
if (studentView) {
role = UserRole.Student;
}
if (!user) {
return null;
}
const librariesMeta = libraries?.meta ?? {
total: 0,
per_page: 20,
page: 1,
current_page: 1,
last_page: 1
};

const handleSetPerPage = (perPage: number) => {
setPerPage(perPage);
setPageQuery(1);
void mutateLibraries();
};

return (
<div className="pt-6 space-y-6">
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/Components/MilestonesBarChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@ import { useContext } from 'react';
import { CourseMilestones, YAxisTickProps } from '@/common';

const maxYAxisLabel = (props: YAxisTickProps) => {
const { theme } = useContext(ThemeContext);
const fill = theme == 'light' ? '#666' : '#CCC';
const fill = props.theme == 'light' ? '#666' : '#CCC';

const { x, y, payload } = props;
const name = payload.value;
Expand Down
19 changes: 12 additions & 7 deletions frontend/src/Components/forms/ChangePasswordForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,15 @@ import InputError from '../../Components/inputs/InputError';
import PrimaryButton from '../../Components/PrimaryButton';
import { TextInput } from '../../Components/inputs/TextInput';
import { CheckIcon, XMarkIcon } from '@heroicons/react/24/solid';
import { useAuth } from '@/useAuth';
import API from '@/api/api';
import { AuthResponse, Facility, ServerResponseOne, UserRole } from '@/common';
import {
AuthResponse,
DEFAULT_ADMIN_FACILITY,
DEFAULT_ADMIN_ID,
ServerResponseOne,
User,
UserRole
} from '@/common';
import { useLoaderData } from 'react-router-dom';
interface Inputs {
password: string;
Expand All @@ -17,8 +23,7 @@ interface Inputs {
export default function ChangePasswordForm() {
const [errorMessage, setErrorMessage] = useState('');
const [processing, setProcessing] = useState(false);
const loaderData = useLoaderData() as Facility | null;
const { user } = useAuth();
const user = useLoaderData() as User;

const {
control,
Expand Down Expand Up @@ -50,9 +55,9 @@ export default function ChangePasswordForm() {
const validFacility =
facility && facility.length > 2 && facility.trim().length > 2;
const isFirstAdminLogin =
user?.id === 1 &&
user?.role === UserRole.Admin &&
loaderData?.name === 'Default';
user.id === DEFAULT_ADMIN_ID &&
user.role === UserRole.Admin &&
user.facility_name === DEFAULT_ADMIN_FACILITY;

const submit: SubmitHandler<Inputs> = async (data) => {
setErrorMessage('');
Expand Down
11 changes: 5 additions & 6 deletions frontend/src/Components/forms/MapUserForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ export default function MapUserForm({
) : fuzzySearchUsers?.length != 0 && !seeAllUsers ? (
<>
<p className="body-small mb-2">
We have found a potential match to the student you'd
like to map:
We have found a potential match to the student
you&aposd like to map:
</p>
{fuzzySearchUsers?.map((user: User) => {
return (
Expand Down Expand Up @@ -168,10 +168,9 @@ export default function MapUserForm({
)}
{unmappedUsers?.map((user: User) => {
return (
<UserRadioInput
user={user}
key={'allUsers' + user.id}
/>
<p key={user.id}>
<UserRadioInput user={user} />
</p>
);
})}
{meta && (
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/Components/forms/RegisterOidcClientForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export default function RegisterOidcClientForm({
<div className="label-text text-warning font-semibold">
If you do not choose to auto register, you must manually
setup authentication for UnlockEd the provider
platform's settings.
platform&aposs settings.
</div>
)}
<label className="label-text text-md font-semibold">
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/Components/forms/ResetPasswordForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default function ResetPasswordForm({
<div>
<p>
Are you sure you would like to reset {user?.name_first}{' '}
{user?.name_last}'s password?
{user?.name_last}&aposs password?
</p>
<p className="py-4"></p>
<div className="flex flex-row justify-between">
Expand Down
Loading

0 comments on commit 171d659

Please sign in to comment.