Skip to content

Commit a2f1e99

Browse files
committed
Refactor SPA code
1 parent 3e9be59 commit a2f1e99

File tree

3 files changed

+162
-152
lines changed

3 files changed

+162
-152
lines changed

client/src/App.js

+6-152
Original file line numberDiff line numberDiff line change
@@ -1,161 +1,15 @@
1-
import React, { useState, useEffect } from 'react';
2-
import { PublicClientApplication } from '@azure/msal-browser';
1+
import React from 'react';
32
import { Buffer } from 'buffer';
3+
import { AuthProvider } from './components/AuthProvider';
4+
import CsvUploader from './components/CsvUploader';
45

56
window.Buffer = Buffer;
67

7-
// MSAL Configuration
8-
const msalConfig = {
9-
auth: {
10-
clientId: process.env.REACT_APP_STATIC_WEB_APP_CLIENT_ID,
11-
authority: `https://login.microsoftonline.com/${process.env.REACT_APP_AZURE_TENANT_ID}`,
12-
redirectUri: window.location.origin,
13-
},
14-
};
15-
16-
const msalInstance = new PublicClientApplication(msalConfig);
17-
188
const App = () => {
19-
const [file, setFile] = useState(null);
20-
const [error, setError] = useState('');
21-
const [modalVisible, setModalVisible] = useState(false);
22-
const [user, setUser] = useState(null);
23-
const [isInitialized, setIsInitialized] = useState(false);
24-
25-
const handleFileChange = (e) => {
26-
setError('');
27-
setFile(e.target.files[0]);
28-
};
29-
30-
const uploadFile = async (file) => {
31-
if (!file) {
32-
setError('Please select a file to upload');
33-
return;
34-
}
35-
36-
try {
37-
console.log('Authenticating and uploading file...');
38-
39-
// Acquire access token
40-
const account = msalInstance.getAllAccounts()[0];
41-
if (!account) {
42-
throw new Error('User is not signed in');
43-
}
44-
45-
const tokenResponse = await msalInstance.acquireTokenSilent({
46-
scopes: ['api://hvalfangst-function-app/Csv.Writer'],
47-
account
48-
});
49-
50-
console.log('Token response:', tokenResponse);
51-
52-
const token = tokenResponse.accessToken;
53-
54-
const endpoint = 'https://hvalfangstlinuxfunctionapp.azurewebsites.net/api/upload_csv';
55-
56-
// Read the file as a text string
57-
const fileContent = await file.text();
58-
59-
const response = await fetch(endpoint, {
60-
method: 'POST',
61-
headers: {
62-
'Content-Type': 'text/csv', // Set content type to CSV
63-
Authorization: `Bearer ${token}`, // Include OAuth token
64-
},
65-
body: fileContent, // Send the file content as the body
66-
});
67-
68-
if (!response.ok) {
69-
const errorMessage = await response.text();
70-
throw new Error(`Failed to upload: ${errorMessage}`);
71-
}
72-
73-
console.log('Response:', response)
74-
75-
console.log('File uploaded successfully');
76-
setModalVisible(true); // Show success modal
77-
} catch (error) {
78-
console.error('Error uploading file:', error);
79-
setError(`Error uploading file: ${error.message}`);
80-
}
81-
};
82-
83-
const handleFileUpload = () => {
84-
if (file) {
85-
uploadFile(file);
86-
} else {
87-
setError('Please select a file to upload');
88-
}
89-
};
90-
91-
const closeModal = () => {
92-
setModalVisible(false);
93-
};
94-
95-
const handleSignIn = async () => {
96-
try {
97-
await msalInstance.initialize();
98-
setIsInitialized(true);
99-
const response = await msalInstance.loginPopup({
100-
scopes: ['openid'],
101-
});
102-
console.log('Sign in response:', response);
103-
console.log('User signed in successfully');
104-
setUser(response.account);
105-
} catch (error) {
106-
console.error('Error signing in:', error);
107-
setError(`Error signing in: ${error.message}`);
108-
}
109-
};
110-
111-
const handleSignOut = async () => {
112-
if (!isInitialized) {
113-
console.error('MSAL instance is not initialized.');
114-
return;
115-
}
116-
await msalInstance.logoutPopup();
117-
setUser(null);
118-
};
119-
120-
useEffect(() => {
121-
const initializeMsal = async () => {
122-
await msalInstance.initialize();
123-
setIsInitialized(true);
124-
const accounts = msalInstance.getAllAccounts();
125-
if (accounts.length > 0) {
126-
setUser(accounts[0]);
127-
}
128-
};
129-
130-
initializeMsal();
131-
}, []);
132-
1339
return (
134-
<div className="csv-uploader">
135-
<h1>CSV Uploader</h1>
136-
{user ? (
137-
<div>
138-
<p>Welcome, {user.name}</p>
139-
<button onClick={handleSignOut}>Sign Out</button>
140-
</div>
141-
) : (
142-
<button onClick={handleSignIn}>Sign In</button>
143-
)}
144-
145-
<input type="file" accept=".csv" onChange={handleFileChange} />
146-
<button onClick={handleFileUpload}>Upload</button>
147-
{error && <p className="error">{error}</p>}
148-
149-
{modalVisible && (
150-
<div className="modal">
151-
<div className="modal-content">
152-
<h2>Upload Successful!</h2>
153-
<p>Your file has been uploaded to Azure Blob Storage via Azure Function.</p>
154-
<button onClick={closeModal}>Close</button>
155-
</div>
156-
</div>
157-
)}
158-
</div>
10+
<AuthProvider>
11+
<CsvUploader />
12+
</AuthProvider>
15913
);
16014
};
16115

client/src/components/AuthProvider.js

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import React, { createContext, useContext, useState, useEffect } from 'react';
2+
import { PublicClientApplication } from '@azure/msal-browser';
3+
4+
const AuthContext = createContext();
5+
6+
const msalConfig = {
7+
auth: {
8+
clientId: process.env.REACT_APP_STATIC_WEB_APP_CLIENT_ID,
9+
authority: `https://login.microsoftonline.com/${process.env.REACT_APP_AZURE_TENANT_ID}`,
10+
redirectUri: window.location.origin,
11+
},
12+
};
13+
14+
const msalInstance = new PublicClientApplication(msalConfig);
15+
16+
export const AuthProvider = ({ children }) => {
17+
const [user, setUser] = useState(null);
18+
const [isInitialized, setIsInitialized] = useState(false);
19+
20+
const getCurrentAccount = () => {
21+
const accounts = msalInstance.getAllAccounts();
22+
return accounts.length > 0 ? accounts[0] : null;
23+
};
24+
25+
const acquireToken = async (scopes) => {
26+
const account = getCurrentAccount();
27+
if (!account) {
28+
throw new Error('No account found');
29+
}
30+
return await msalInstance.acquireTokenSilent({
31+
scopes,
32+
account,
33+
});
34+
};
35+
36+
const handleSignIn = async () => {
37+
try {
38+
await msalInstance.initialize();
39+
setIsInitialized(true);
40+
const response = await msalInstance.loginPopup({
41+
scopes: ['openid'],
42+
});
43+
setUser(response.account);
44+
} catch (error) {
45+
console.error('Error signing in:', error);
46+
}
47+
};
48+
49+
const handleSignOut = async () => {
50+
if (!isInitialized) {
51+
console.error('MSAL instance is not initialized.');
52+
return;
53+
}
54+
await msalInstance.logoutPopup();
55+
setUser(null);
56+
};
57+
58+
return (
59+
<AuthContext.Provider value={{ user, handleSignIn, handleSignOut, acquireToken }}>
60+
{children}
61+
</AuthContext.Provider>
62+
);
63+
};
64+
65+
export const useAuth = () => useContext(AuthContext);

client/src/components/CsvUploader.js

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
import React, { useState } from 'react';
2+
import { useAuth } from './AuthProvider';
3+
import Modal from './Modal';
4+
5+
6+
const CsvUploader = () => {
7+
const { user, handleSignIn, handleSignOut, acquireToken } = useAuth();
8+
const [file, setFile] = useState(null);
9+
const [error, setError] = useState('');
10+
const [modalVisible, setModalVisible] = useState(false);
11+
12+
const handleFileChange = (e) => {
13+
setError('');
14+
setFile(e.target.files[0]);
15+
};
16+
17+
const uploadFile = async (file) => {
18+
if (!file) {
19+
setError('Please select a file to upload');
20+
return;
21+
}
22+
23+
try {
24+
console.log('Authenticating and uploading file...');
25+
const tokenResponse = acquireToken(['api://hvalfangst-function-app/Csv.Writer']);
26+
const accessToken = tokenResponse.accessToken;
27+
const endpoint = 'https://hvalfangstlinuxfunctionapp.azurewebsites.net/api/upload_csv';
28+
const fileContent = await file.text();
29+
30+
const response = await fetch(endpoint, {
31+
method: 'POST',
32+
headers: {
33+
'Content-Type': 'text/csv',
34+
Authorization: `Bearer ${accessToken}`,
35+
},
36+
body: fileContent,
37+
});
38+
39+
if (!response.ok) {
40+
const errorMessage = await response.text();
41+
throw new Error(`Failed to upload: ${errorMessage}`);
42+
}
43+
44+
setModalVisible(true);
45+
} catch (error) {
46+
console.error('Error uploading file:', error);
47+
setError(`Error uploading file: ${error.message}`);
48+
}
49+
};
50+
51+
const handleFileUpload = async () => {
52+
if (file) {
53+
await uploadFile(file);
54+
} else {
55+
setError('Please select a file to upload');
56+
}
57+
};
58+
59+
const closeModal = () => {
60+
setModalVisible(false);
61+
};
62+
63+
return (
64+
<div className="csv-uploader">
65+
<div>
66+
<h1>CSV Uploader</h1>
67+
{user ? (
68+
<div>
69+
<p>Welcome, {user.name}</p>
70+
<button onClick={handleSignOut}>Sign Out</button>
71+
</div>
72+
) : (
73+
<button onClick={handleSignIn}>Sign In</button>
74+
)}
75+
</div>
76+
<div>
77+
<input type="file" accept=".csv" onChange={handleFileChange} />
78+
<button onClick={handleFileUpload}>Upload</button>
79+
{error && <p className="error">{error}</p>}
80+
</div>
81+
{modalVisible && (
82+
<Modal onClose={closeModal}>
83+
<p>File uploaded successfully!</p>
84+
<button onClick={closeModal}>Close</button>
85+
</Modal>
86+
)}
87+
</div>
88+
);
89+
};
90+
91+
export default CsvUploader;

0 commit comments

Comments
 (0)