V 0.1.3
This commit is contained in:
		
							
								
								
									
										6366
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										6366
									
								
								pnpm-lock.yaml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -47,9 +47,11 @@ export function ApiKeyItem({ apiKey, onDelete }: ApiKeyItemProps) {
 | 
			
		||||
    }
 | 
			
		||||
  };
 | 
			
		||||
 | 
			
		||||
  const displayKey = isVisible
 | 
			
		||||
    ? apiKey.key
 | 
			
		||||
    : apiKey.key.substring(0, 4) + "•".repeat(apiKey.key.length - 8) + apiKey.key.substring(apiKey.key.length - 4);
 | 
			
		||||
const displayKey = isVisible
 | 
			
		||||
  ? apiKey.key
 | 
			
		||||
  : (apiKey.key && apiKey.key.length >= 8)
 | 
			
		||||
    ? apiKey.key.substring(0, 4) + "•".repeat(apiKey.key.length - 8) + apiKey.key.substring(apiKey.key.length - 4)
 | 
			
		||||
    : apiKey.key || ""; 
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <Card className="w-full shadow-sm">
 | 
			
		||||
 
 | 
			
		||||
@@ -40,9 +40,9 @@ export function Header() {
 | 
			
		||||
 | 
			
		||||
  return (
 | 
			
		||||
    <header>
 | 
			
		||||
      {/* Alpha Disclaimer */}
 | 
			
		||||
      {/* Beta Disclaimer */}
 | 
			
		||||
      <div className="bg-red-500 text-white text-center py-1 text-sm">
 | 
			
		||||
        Alpha Version – Report any issues to{" "}
 | 
			
		||||
        Beta Version – Report any issues to{" "}
 | 
			
		||||
        <a href="mailto:me@mahdium.ir" className="underline">
 | 
			
		||||
          me@mahdium.ir
 | 
			
		||||
        </a>
 | 
			
		||||
 
 | 
			
		||||
@@ -22,7 +22,7 @@ export function Layout() {
 | 
			
		||||
              mahdium.ir
 | 
			
		||||
            </a>
 | 
			
		||||
          </p>
 | 
			
		||||
          <p>Version 0.0.3 - Alpha</p>
 | 
			
		||||
          <p>Version 0.1.3 - Beta</p>
 | 
			
		||||
        </div>
 | 
			
		||||
      </footer>
 | 
			
		||||
      <Toaster position="top-right" />
 | 
			
		||||
 
 | 
			
		||||
@@ -3,12 +3,12 @@ import { toast } from 'sonner';
 | 
			
		||||
import { getToken, clearToken } from './auth';
 | 
			
		||||
 | 
			
		||||
// Set up API base URLs
 | 
			
		||||
const AUTH_API_URL = 'https://io-a.monasefloadbalancer.ir/auth';
 | 
			
		||||
const DATA_API_URL = 'https://io-e-cf.monasefloadbalancer.ir/api/user';
 | 
			
		||||
const USER_DATA_API_URL = 'https://io-userdata.monasefloadbalancer.ir';
 | 
			
		||||
const DATA_API_URL = 'https://io-data.monasefloadbalancer.ir/api';
 | 
			
		||||
 | 
			
		||||
// Create axios instances
 | 
			
		||||
const authApi = axios.create({
 | 
			
		||||
  baseURL: AUTH_API_URL,
 | 
			
		||||
const userDataApi = axios.create({
 | 
			
		||||
  baseURL: USER_DATA_API_URL,
 | 
			
		||||
  headers: {
 | 
			
		||||
    'Content-Type': 'application/json',
 | 
			
		||||
  },
 | 
			
		||||
@@ -33,6 +33,17 @@ dataApi.interceptors.request.use(
 | 
			
		||||
  (error) => Promise.reject(error)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
userDataApi.interceptors.request.use(
 | 
			
		||||
  (config) => {
 | 
			
		||||
    const token = getToken();
 | 
			
		||||
    if (token) {
 | 
			
		||||
      config.headers.Authorization = `Bearer ${token}`;
 | 
			
		||||
    }
 | 
			
		||||
    return config;
 | 
			
		||||
  },
 | 
			
		||||
  (error) => Promise.reject(error)
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
// Add response interceptor to handle unauthorized errors
 | 
			
		||||
const handleUnauthorized = (error: any) => {
 | 
			
		||||
  if (error.response && error.response.status === 401) {
 | 
			
		||||
@@ -45,12 +56,12 @@ const handleUnauthorized = (error: any) => {
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
dataApi.interceptors.response.use((response) => response, handleUnauthorized);
 | 
			
		||||
authApi.interceptors.response.use((response) => response, handleUnauthorized);
 | 
			
		||||
userDataApi.interceptors.response.use((response) => response, handleUnauthorized);
 | 
			
		||||
 | 
			
		||||
// Auth API functions
 | 
			
		||||
export const registerUser = async (username: string, password: string, email: string) => {
 | 
			
		||||
  try {
 | 
			
		||||
    const response = await authApi.post('/register', { username, password, email });
 | 
			
		||||
    const response = await userDataApi.post('/auth/register', { username, password, email });
 | 
			
		||||
    return response.data;
 | 
			
		||||
  } catch (error: any) {
 | 
			
		||||
    throw error.response?.data || { success: false, message: 'Network error' };
 | 
			
		||||
@@ -59,7 +70,7 @@ export const registerUser = async (username: string, password: string, email: st
 | 
			
		||||
 | 
			
		||||
export const loginUser = async (username: string, password: string) => {
 | 
			
		||||
  try {
 | 
			
		||||
    const response = await authApi.post('/login', { username, password });
 | 
			
		||||
    const response = await userDataApi.post('/auth/login', { username, password });
 | 
			
		||||
    return response.data;
 | 
			
		||||
  } catch (error: any) {
 | 
			
		||||
    throw error.response?.data || { success: false, message: 'Network error' };
 | 
			
		||||
@@ -69,16 +80,44 @@ export const loginUser = async (username: string, password: string) => {
 | 
			
		||||
// Data API functions
 | 
			
		||||
export const getAllFeeds = async () => {
 | 
			
		||||
  try {
 | 
			
		||||
    const response = await dataApi.get('/GetAllFeeds');
 | 
			
		||||
    const response = await userDataApi.get('/api/getallfeeds');
 | 
			
		||||
    return response.data;
 | 
			
		||||
  } catch (error: any) {
 | 
			
		||||
    throw error.response?.data || { success: false, message: 'Network error' };
 | 
			
		||||
  }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const addNewFeed = async () => {
 | 
			
		||||
export const updateFeed = async (feedId: string, name: string, isPublic: boolean) => {
 | 
			
		||||
  const token = getToken();
 | 
			
		||||
  if (!token) throw new Error('Authentication required');
 | 
			
		||||
 | 
			
		||||
  const response = await userDataApi.patch('/api/updatefeed', {
 | 
			
		||||
    feedId,
 | 
			
		||||
    Name: name,
 | 
			
		||||
    IsPublic: isPublic,
 | 
			
		||||
  }, {
 | 
			
		||||
    headers: {
 | 
			
		||||
      Authorization: `Bearer ${token}`
 | 
			
		||||
    }
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return response.data;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export const addNewFeed = async (name: string, isPublic: boolean) => {
 | 
			
		||||
  const token = getToken();
 | 
			
		||||
  if (!token) throw new Error('Authentication required');
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    const response = await dataApi.get('/AddNewFeed');
 | 
			
		||||
    const response = await userDataApi.post('/api/addnewfeed', {
 | 
			
		||||
      Name: name,
 | 
			
		||||
      IsPublic: isPublic
 | 
			
		||||
    }, {
 | 
			
		||||
      headers: {
 | 
			
		||||
        Authorization: `Bearer ${token}`,
 | 
			
		||||
        'Content-Type': 'application/json'
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    return response.data;
 | 
			
		||||
  } catch (error: any) {
 | 
			
		||||
    throw error.response?.data || { success: false, message: 'Network error' };
 | 
			
		||||
@@ -87,7 +126,7 @@ export const addNewFeed = async () => {
 | 
			
		||||
 | 
			
		||||
export const deleteFeed = async (feedId: string) => {
 | 
			
		||||
  try {
 | 
			
		||||
    const response = await dataApi.delete('/DeleteFeed', {
 | 
			
		||||
    const response = await userDataApi.delete('/api/deletefeed', {
 | 
			
		||||
      data: { feedId }
 | 
			
		||||
    });
 | 
			
		||||
    return response.data;
 | 
			
		||||
@@ -102,7 +141,7 @@ export const getFeedDataTimeRange = async (
 | 
			
		||||
  endTime: string
 | 
			
		||||
) => {
 | 
			
		||||
  try {
 | 
			
		||||
    const response = await dataApi.get(`/GetFeedDataTimeRange/${feedId}/${startTime}/${endTime}`);
 | 
			
		||||
    const response = await dataApi.get(`/dash/getfeeddatatimerange/${feedId}/${startTime}/${endTime}`);
 | 
			
		||||
    return response.data;
 | 
			
		||||
  } catch (error: any) {
 | 
			
		||||
    throw error.response?.data || { success: false, message: 'Network error' };
 | 
			
		||||
@@ -117,7 +156,7 @@ export const createApiKey = async () => {
 | 
			
		||||
      throw new Error('Authentication required');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const response = await authApi.get('/createapikey', {
 | 
			
		||||
    const response = await userDataApi.get('/api/createapikey', {
 | 
			
		||||
      headers: {
 | 
			
		||||
        Authorization: `Bearer ${token}`
 | 
			
		||||
      }
 | 
			
		||||
@@ -135,7 +174,7 @@ export const getUserApiKeys = async () => {
 | 
			
		||||
      throw new Error('Authentication required');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const response = await authApi.get('/getuserapikeys', {
 | 
			
		||||
    const response = await userDataApi.get('/api/getuserapikeys', {
 | 
			
		||||
      headers: {
 | 
			
		||||
        Authorization: `Bearer ${token}`
 | 
			
		||||
      }
 | 
			
		||||
@@ -153,7 +192,7 @@ export const deleteApiKey = async (ApiKey: string) => {
 | 
			
		||||
      throw new Error('Authentication required');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const response = await authApi.delete('/deleteapikey', {
 | 
			
		||||
    const response = await userDataApi.delete('/api/deleteapikey', {
 | 
			
		||||
      headers: {
 | 
			
		||||
        Authorization: `Bearer ${token}`
 | 
			
		||||
      },
 | 
			
		||||
@@ -168,7 +207,7 @@ export const deleteApiKey = async (ApiKey: string) => {
 | 
			
		||||
export const verifyEmail = async (token: string) => {
 | 
			
		||||
  try {
 | 
			
		||||
    // Call the verify email endpoint with no extra headers or data
 | 
			
		||||
    const response = await authApi.get(`/verifyemail/${token}`);
 | 
			
		||||
    const response = await userDataApi.get(`/auth/verifyemail/${token}`);
 | 
			
		||||
    return response.data;
 | 
			
		||||
  } catch (error: any) {
 | 
			
		||||
    throw error.response?.data || { success: false, message: 'Network error' };
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@ export interface ApiKeyResponse {
 | 
			
		||||
  apiKey: string;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// New ApiKey Type
 | 
			
		||||
// New ApiKey Typez
 | 
			
		||||
export interface ApiKey {
 | 
			
		||||
  createdAt: string;
 | 
			
		||||
  key: string;
 | 
			
		||||
 
 | 
			
		||||
@@ -33,10 +33,14 @@ export function ApiKeysPage() {
 | 
			
		||||
  const fetchApiKeys = async () => {
 | 
			
		||||
    setIsLoading(true);
 | 
			
		||||
    setError(null);
 | 
			
		||||
 | 
			
		||||
  
 | 
			
		||||
    try {
 | 
			
		||||
      const keys = await getUserApiKeys();
 | 
			
		||||
      setApiKeys(keys);
 | 
			
		||||
      const normalizedKeys: ApiKey[] = keys.map((item: { createdAt: any; apiKey: any; }) => ({
 | 
			
		||||
        createdAt: item.createdAt,
 | 
			
		||||
        key: item.apiKey,
 | 
			
		||||
      }));
 | 
			
		||||
      setApiKeys(normalizedKeys);
 | 
			
		||||
    } catch (err: any) {
 | 
			
		||||
      setError(err.message || "Failed to fetch API keys");
 | 
			
		||||
    } finally {
 | 
			
		||||
 
 | 
			
		||||
@@ -56,23 +56,22 @@ export function HomePage() {
 | 
			
		||||
        <div className="grid gap-8 md:grid-cols-3">
 | 
			
		||||
          <div className="flex flex-col items-center text-center p-6 rounded-lg border bg-card shadow-sm">
 | 
			
		||||
            <LineChart className="h-12 w-12 text-primary mb-4" />
 | 
			
		||||
            <h3 className="text-xl font-semibold mb-2">Real-time Visualization</h3>
 | 
			
		||||
            <h3 className="text-xl font-semibold mb-2">Time-based Visualization</h3>
 | 
			
		||||
            <p className="text-muted-foreground">
 | 
			
		||||
              Monitor your IoT device data in real-time with interactive charts and customizable
 | 
			
		||||
              Monitor your IoT device data in thoughout time with interactive charts and customizable
 | 
			
		||||
              dashboards
 | 
			
		||||
            </p>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div className="flex flex-col items-center text-center p-6 rounded-lg border bg-card shadow-sm">
 | 
			
		||||
            <ShieldCheck className="h-12 w-12 text-primary mb-4" />
 | 
			
		||||
            <h3 className="text-xl font-semibold mb-2">Secure Communication</h3>
 | 
			
		||||
            <Zap className="h-12 w-12 text-primary mb-4" />
 | 
			
		||||
            <h3 className="text-xl font-semibold mb-2">Lightning-Fast Data Access</h3>
 | 
			
		||||
            <p className="text-muted-foreground">
 | 
			
		||||
              Industry-standard encryption and authentication for all your IoT communications
 | 
			
		||||
            </p>
 | 
			
		||||
            Instantly retrieve and analyze your IoT data with high-speed querying, powered by specialized time-series databases optimized for rapid communication and real-time performance.            </p>
 | 
			
		||||
          </div>
 | 
			
		||||
 | 
			
		||||
          <div className="flex flex-col items-center text-center p-6 rounded-lg border bg-card shadow-sm">
 | 
			
		||||
            <Zap className="h-12 w-12 text-primary mb-4" />
 | 
			
		||||
          <ShieldCheck className="h-12 w-12 text-primary mb-4" />
 | 
			
		||||
            <h3 className="text-xl font-semibold mb-2">Simple Integration</h3>
 | 
			
		||||
            <p className="text-muted-foreground">
 | 
			
		||||
              Easy-to-use API with comprehensive documentation for quick integration with any device
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user