Skip to content

Commit

Permalink
initial code
Browse files Browse the repository at this point in the history
  • Loading branch information
Caerlower committed Jul 16, 2024
0 parents commit 1e4bc0d
Show file tree
Hide file tree
Showing 38 changed files with 2,250 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.env
node_modules
86 changes: 86 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
socialfi-music-dapp/
├── contracts/ # Aptos Move Smart Contracts
│ ├── music_nft.move # Handles NFT creation, ownership, metadata
│ ├── royalty_distribution.move # Manages splitting of royalties to NFT owners, artists, platform
│ ├── fractional_ownership.move # Allows for partial ownership of NFTs
│ ├── tip_jar.move # Securely handles direct artist tipping
│ ├── governance.move # (Optional) Community voting on platform decisions
│ ├── token.move # (Optional) If using social tokens for community membership
│ └── ... # Other contracts as needed (e.g., for subscriptions)
├── client/ # Frontend (Web App)
│ ├── public/ # Static assets
│ │ ├── index.html
│ │ ├── favicon.ico
│ │ ├── logo.png
│ │ └── ...
│ ├── src/ # Source code
│ │ ├── components/ # Reusable UI elements
│ │ │ ├── MusicNFTCard.jsx
│ │ │ ├── ArtistProfile.jsx
│ │ │ ├── LiveStreamPlayer.jsx
│ │ │ ├── FanClubChat.jsx
│ │ │ ├── TipJar.jsx
│ │ │ └── ...
│ │ ├── pages/ # Main views
│ │ │ ├── Home.jsx # Music feed
│ │ │ ├── Explore.jsx # Discover new artists
│ │ │ ├── ArtistPage.jsx
│ │ │ ├── FanClubPage.jsx
│ │ │ └── ...
│ │ ├── utils/ # Helper functions
│ │ │ ├── aptos.js # Aptos SDK interaction (transactions, etc.)
│ │ │ ├── nft.js # NFT handling (metadata, image display, etc.) --- API: 66c8607b.997e5e6cd4be4dd8aa3560fed7d31fa5
│ │ │ ├── web3Storage.js # (Optional) For decentralized storage
│ │ │ └── ...
│ │ ├── context/ # (Optional) Context API for global state
│ │ ├── hooks/ # Custom React hooks
│ │ ├── store/ # (Optional) If using Redux/Zustand
│ │ ├── App.jsx
│ │ ├── index.jsx
│ │ └── ...
│ ├── package.json
│ ├── .env # Environment variables
│ └── ...
server/
├── src/ # Source code
│ ├── app.js # Main application entry point (or index.js)
│ ├── routes/ # API route definitions
│ │ ├── artists.js
│ │ ├── nfts.js
│ │ ├── fanclubs.js
│ │ ├── live-streams.js
│ │ └── auth.js # (For authentication/authorization)
│ ├── controllers/ # Logic for handling API requests
│ │ ├── artists.js
│ │ ├── nfts.js
│ │ ├── fanclubs.js
│ │ ├── live-streams.js
│ │ └── auth.js
│ ├── middleware/
│ │ ├── auth.js
│ │ └── errorHandler.js
│ ├── utils/ # Helper functions (e.g., Aptos interaction)
│ │ ├── aptos.js # Interaction with Aptos blockchain
│ │ ├── caching.js # (Optional) Caching to reduce blockchain reads
│ │ └── ...
│ └── index.js # (If using a different entry point than app.js)
├── public/ # Static files (if needed)
│ ├── images/
│ └── ...
├── tests/ # Unit and integration tests
│ ├── routes/
│ ├── controllers/
│ └── ...
│ ├── package.json
│ └── ...
├── scripts/ # Deployment scripts
│ ├── deploy_contracts.sh
│ ├── setup_testnet.sh
│ └── ...
├── tests/ # Unit, integration tests
│ ├── contracts/
│ ├── client/
│ ├── server/
│ └── ...
├── .gitignore
├── README.md # Project documentation
Empty file added client/public/favicon.ico
Empty file.
21 changes: 21 additions & 0 deletions client/public/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SocialFi Music dApp</title>
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />

<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">

<script src="https://unpkg.com/@aptos-labs/wallet-adapter-react"></script>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>

<script src="https://unpkg.com/web3modal"></script>

<script src="%PUBLIC_URL%/bundle.js"></script>
</body>
</html>
Empty file added client/public/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
81 changes: 81 additions & 0 deletions client/src/App.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React, { useEffect } from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import { WalletProvider, useWallet } from '@aptos-labs/wallet-adapter-react';
import { PetraWallet, MartianWallet } from 'petra-plugin-wallet-adapter';
import { createTheme, ThemeProvider, CssBaseline, Box, CircularProgress } from '@mui/material';
import { ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import Home from './pages/Home';
import Explore from './pages/Explore';
import ArtistPage from './pages/ArtistPage';
import FanClubPage from './pages/FanClubPage';
import Navbar from './components/Navbar';

// Custom theme for Material UI
const theme = createTheme({
// ... your custom theme settings
});

function AppContent() {
const { connected, connect } = useWallet();
const [isLoading, setIsLoading] = useState(true);

useEffect(() => {
const connectWallet = async () => {
try {
await connect();
setIsLoading(false);
} catch (error) {
console.error('Error connecting wallet:', error);
toast.error('Could not connect wallet'); // Display error message to user
}
};

if (!connected) {
connectWallet();
} else {
setIsLoading(false); // If already connected, remove loading state
}
}, [connected]);

return (
<ThemeProvider theme={theme}>
<CssBaseline />
<Router>
<Navbar />
<ToastContainer />
{isLoading ? ( // Show loading indicator until wallet is connected
<Box sx={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
<CircularProgress />
</Box>
) : (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/explore" element={<Explore />} />
<Route path="/artist/:artistAddress" element={<ArtistPage />} />
<Route path="/fanclub/:artistAddress" element={<FanClubPage />} />
{/* ... other routes as needed */}
</Routes>
)}
</Router>
</ThemeProvider>
);
}

function App() {
const wallets = [
new PetraWallet(),
new MartianWallet()
];

return (
<WalletProvider
wallets={wallets}
autoConnect={true}
>
<AppContent />
</WalletProvider>
);
}

export default App;
73 changes: 73 additions & 0 deletions client/src/components/ArtistProfile.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import React, { useState, useEffect } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { useWallet } from '@aptos-labs/wallet-adapter-react';
import { AptosClient, Types } from 'aptos';
import { toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import MusicNFTCard from './MusicNFTCard';
import FanClubChat from './FanClubChat';
import { getArtistProfile, getNFTsByArtist } from '../utils/aptos'; // Assuming you have these utility functions

const nodeUrl = 'https://fullnode.devnet.aptoslabs.com/v1';
const client = new AptosClient(nodeUrl);

const ArtistProfile = () => {
const { artistAddress } = useParams();
const { account } = useWallet();
const navigate = useNavigate();
const [artistNFTs, setArtistNFTs] = useState([]);
const [artistProfile, setArtistProfile] = useState(null);

useEffect(() => {
const fetchData = async () => {
try {
const profile = await getArtistProfile(client, artistAddress);
if (profile) {
setArtistProfile(profile);
} else {
toast.error('Artist profile not found.');
navigate('/'); // Redirect to home if profile doesn't exist
}

const nfts = await getNFTsByArtist(client, artistAddress);
setArtistNFTs(nfts);
} catch (error) {
console.error('Error fetching artist data:', error);
toast.error('Error fetching artist data.');
}
};
fetchData();
}, [artistAddress, navigate]);

// ... (handleNFTPurchase and generateTransactionPayload functions remain the same)

return (
<div className="artist-profile">
{artistProfile ? (
<>
{/* ... (artist profile display) */}
</>
) : (
<p>Loading artist profile...</p> // Display loading message
)}

<h3>NFTs</h3>
{!artistNFTs.length ? (
<p>No NFTs found for this artist.</p>
) : (
<div className="nft-grid">
{artistNFTs.map((nft) => (
<MusicNFTCard
key={nft.tokenId}
nft={nft}
onBuy={handleNFTPurchase}
connectedWalletAddress={account?.address}
/>
))}
</div>
)}
</div>
);
};

export default ArtistProfile;
83 changes: 83 additions & 0 deletions client/src/components/FanClubChat.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, { useState, useEffect, useRef } from 'react';
import { useParams } from 'react-router-dom';
import { useWallet } from '@aptos-labs/wallet-adapter-react';

const FanClubChat = ({ artistAddress }) => {
const { connected, account } = useWallet();
const [messages, setMessages] = useState([]);
const [newMessage, setNewMessage] = useState('');
const chatContainerRef = useRef(null);

useEffect(() => {
// Fetch initial messages from the backend
const fetchMessages = async () => {
try {
const response = await fetch(`/api/fanclubs/${artistAddress}/messages`);
const data = await response.json();
setMessages(data);
} catch (error) {
console.error('Error fetching messages:', error);
}
};
fetchMessages();

// Set up real-time updates (e.g., WebSockets, polling)
// ... (Implementation depends on your backend/chat service)
}, [artistAddress]);

useEffect(() => {
// Auto-scroll to the bottom when new messages arrive
if (chatContainerRef.current) {
chatContainerRef.current.scrollTop = chatContainerRef.current.scrollHeight;
}
}, [messages]);

const handleSendMessage = async () => {
if (!connected || !account) {
alert('Please connect your wallet to join the chat.');
return;
}

try {
const response = await fetch(`/api/fanclubs/${artistAddress}/messages`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sender: account.address,
content: newMessage
})
});

if (response.ok) {
setNewMessage('');
// Fetch updated messages (or update via real-time updates)
} else {
console.error('Error sending message:', response.statusText);
}
} catch (error) {
console.error('Error sending message:', error);
}
};

return (
<div className="fan-club-chat">
<div className="chat-messages" ref={chatContainerRef}>
{messages.map((message, index) => (
<div key={index} className={`message ${message.sender === account?.address ? 'sent' : 'received'}`}>
<p>{message.content}</p>
</div>
))}
</div>
<div className="chat-input">
<input
type="text"
value={newMessage}
onChange={(e) => setNewMessage(e.target.value)}
/>
<button onClick={handleSendMessage}>Send</button>
</div>
</div>
);
};

export default FanClubChat;
Loading

0 comments on commit 1e4bc0d

Please sign in to comment.